]> granicus.if.org Git - postgresql/commitdiff
Move exprType(), exprTypmod(), expression_tree_walker(), and related routines
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 25 Aug 2008 22:42:34 +0000 (22:42 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 25 Aug 2008 22:42:34 +0000 (22:42 +0000)
into nodes/nodeFuncs, so as to reduce wanton cross-subsystem #includes inside
the backend.  There's probably more that should be done along this line,
but this is a start anyway.

55 files changed:
src/backend/catalog/dependency.c
src/backend/catalog/heap.c
src/backend/catalog/index.c
src/backend/commands/analyze.c
src/backend/commands/indexcmds.c
src/backend/commands/prepare.c
src/backend/commands/tablecmds.c
src/backend/commands/view.c
src/backend/executor/execMain.c
src/backend/executor/execQual.c
src/backend/executor/execTuples.c
src/backend/executor/functions.c
src/backend/executor/nodeAgg.c
src/backend/nodes/README
src/backend/nodes/nodeFuncs.c
src/backend/optimizer/path/allpaths.c
src/backend/optimizer/path/costsize.c
src/backend/optimizer/path/equivclass.c
src/backend/optimizer/path/pathkeys.c
src/backend/optimizer/path/tidpath.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/planagg.c
src/backend/optimizer/plan/setrefs.c
src/backend/optimizer/plan/subselect.c
src/backend/optimizer/prep/prepjointree.c
src/backend/optimizer/prep/prepunion.c
src/backend/optimizer/util/clauses.c
src/backend/optimizer/util/plancat.c
src/backend/optimizer/util/predtest.c
src/backend/optimizer/util/tlist.c
src/backend/optimizer/util/var.c
src/backend/parser/analyze.c
src/backend/parser/parse_agg.c
src/backend/parser/parse_clause.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_func.c
src/backend/parser/parse_node.c
src/backend/parser/parse_oper.c
src/backend/parser/parse_relation.c
src/backend/parser/parse_target.c
src/backend/parser/parse_utilcmd.c
src/backend/rewrite/rewriteDefine.c
src/backend/rewrite/rewriteHandler.c
src/backend/rewrite/rewriteManip.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/adt/selfuncs.c
src/backend/utils/adt/xml.c
src/backend/utils/cache/plancache.c
src/backend/utils/fmgr/fmgr.c
src/backend/utils/fmgr/funcapi.c
src/include/nodes/nodeFuncs.h
src/include/optimizer/clauses.h
src/include/parser/parse_expr.h
src/pl/plpgsql/src/pl_exec.c

index 0c85ac785fdf67d361d134371f01b26e2401eda0..3521f5ec95228a3f6b1f595e703d430ebda7df0c 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.79 2008/08/22 00:16:03 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.80 2008/08/25 22:42:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -56,7 +56,7 @@
 #include "commands/trigger.h"
 #include "commands/typecmds.h"
 #include "miscadmin.h"
-#include "optimizer/clauses.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteRemove.h"
 #include "storage/lmgr.h"
index c5cea2f67fd065eaf2ba294a87eac7076991c459..499929ef1028531765e54ceea36e334a6e2f567d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.337 2008/08/11 11:05:10 heikki Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.338 2008/08/25 22:42:32 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -50,7 +50,7 @@
 #include "commands/tablecmds.h"
 #include "commands/typecmds.h"
 #include "miscadmin.h"
-#include "optimizer/clauses.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/var.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
index abe8d29ac1658a30851f553382996c6ef6eaf1dc..1847f023e4a997e8d9025c17c624ce95689f5987 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.302 2008/08/11 11:05:10 heikki Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.303 2008/08/25 22:42:32 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -44,9 +44,9 @@
 #include "commands/tablecmds.h"
 #include "executor/executor.h"
 #include "miscadmin.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/var.h"
-#include "parser/parse_expr.h"
 #include "storage/bufmgr.h"
 #include "storage/lmgr.h"
 #include "storage/procarray.h"
index 3b8423999a7948180e41cf98d0644ef36292a12e..c207e502ee826e599da1657d1cb13703e1d12f8a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.124 2008/08/02 21:31:59 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.125 2008/08/25 22:42:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,7 +28,7 @@
 #include "commands/vacuum.h"
 #include "executor/executor.h"
 #include "miscadmin.h"
-#include "parser/parse_expr.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/parse_oper.h"
 #include "parser/parse_relation.h"
 #include "pgstat.h"
index 1427b2a10edc75392569ce87754ef60f58b5a267..cbf440fc438727ba08206d657c9de4d89cebffe8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.178 2008/07/30 17:05:04 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.179 2008/08/25 22:42:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,9 +32,9 @@
 #include "commands/tablespace.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "parser/parse_coerce.h"
-#include "parser/parse_expr.h"
 #include "parser/parse_func.h"
 #include "parser/parsetree.h"
 #include "storage/lmgr.h"
index fe716c5e9f6a9fcbc95ee83f7627e32a62821a0c..2fca3a5e8135612101061ab978799fc528eb4799 100644 (file)
@@ -10,7 +10,7 @@
  * Copyright (c) 2002-2008, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.89 2008/07/21 15:26:55 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.90 2008/08/25 22:42:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,7 @@
 #include "commands/explain.h"
 #include "commands/prepare.h"
 #include "miscadmin.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/analyze.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
index 5167a40927aa86c9b953101992995c514da2c875..a8ae2e4be129156469868e141657ec5a8d9acd98 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.262 2008/08/11 11:05:11 heikki Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.263 2008/08/25 22:42:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,6 +46,7 @@
 #include "executor/executor.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "nodes/parsenodes.h"
 #include "optimizer/clauses.h"
 #include "optimizer/plancat.h"
index e6ec1508ab30bede147acdaf313e254a511feea9..5d207861dca17289da3e5f8d9693bc4dfa34b511 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.106 2008/06/19 00:46:04 alvherre Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.107 2008/08/25 22:42:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,9 +22,8 @@
 #include "commands/view.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
-#include "optimizer/clauses.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/analyze.h"
-#include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
 #include "rewrite/rewriteDefine.h"
 #include "rewrite/rewriteManip.h"
index 3072cf7b045a4ce01ff84253abfac4bc542ad796..49fa4156de4add4aba10cb538620f78654964844 100644 (file)
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.312 2008/08/08 17:01:11 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.313 2008/08/25 22:42:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -45,9 +45,9 @@
 #include "executor/instrument.h"
 #include "executor/nodeSubplan.h"
 #include "miscadmin.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "parser/parse_clause.h"
-#include "parser/parse_expr.h"
 #include "parser/parsetree.h"
 #include "storage/bufmgr.h"
 #include "storage/lmgr.h"
index 57b2df9c00ec1686434141c08cbd0f3ce112bdc6..57b6445c0ff64b51241f435ad710b4fc46d9f881 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.232 2008/08/22 00:16:03 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.233 2008/08/25 22:42:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -44,8 +44,8 @@
 #include "funcapi.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/planmain.h"
-#include "parser/parse_expr.h"
 #include "pgstat.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
index 6ed210b7a6d2fb75849dfe62efdc2cae5821e2fd..357d99e36fc4a724da98134278ab43429291db8d 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.101 2008/05/12 00:00:49 alvherre Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.102 2008/08/25 22:42:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -93,7 +93,7 @@
 
 #include "funcapi.h"
 #include "catalog/pg_type.h"
-#include "parser/parse_expr.h"
+#include "nodes/nodeFuncs.h"
 #include "storage/bufmgr.h"
 #include "utils/lsyscache.h"
 #include "utils/typcache.h"
index 81f0c8e7318d87ef57b59a4c444478a215e68ef9..3ce4d0f321012257f30feb5927d969fefda2fe27 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.125 2008/05/12 20:02:00 alvherre Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.126 2008/08/25 22:42:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,8 +21,8 @@
 #include "executor/functions.h"
 #include "funcapi.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/parse_coerce.h"
-#include "parser/parse_expr.h"
 #include "tcop/tcopprot.h"
 #include "tcop/utility.h"
 #include "utils/builtins.h"
index 9bcff0f8dfec165ba5fa0f31a54bf87949002bd8..fa49862912ee6f05df78860ba63e903264dc7fb0 100644 (file)
@@ -61,7 +61,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.159 2008/08/02 21:31:59 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.160 2008/08/25 22:42:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "executor/executor.h"
 #include "executor/nodeAgg.h"
 #include "miscadmin.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "parser/parse_agg.h"
 #include "parser/parse_coerce.h"
-#include "parser/parse_expr.h"
 #include "parser/parse_oper.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
index b1b95ffcdeeab3bdb34e8f5367f16e4c22db9bde..67e7badc1f37de586f545cae86745d679e65d5fa 100644 (file)
@@ -1,4 +1,4 @@
-$PostgreSQL: pgsql/src/backend/nodes/README,v 1.3 2008/03/20 17:55:14 momjian Exp $
+$PostgreSQL: pgsql/src/backend/nodes/README,v 1.4 2008/08/25 22:42:32 tgl Exp $
 
 Node Structures
 ===============
@@ -13,52 +13,68 @@ achieved by convention. No additional functions will be generated. Functions
 that manipulate node structures reside in this directory.
 
 
-FILES IN THIS DIRECTORY
+FILES IN THIS DIRECTORY (src/backend/nodes/)
 
-    Node manipulation functions:
-       copyfuncs.c     - copying a node
-       equalfuncs.c    - comparing a node
-       outfuncs.c      - convert a node to ascii representation
-       readfuncs.c     - convert ascii representation back to a node
-       makefuncs.c     - creator functions for primitive nodes
+    General-purpose node manipulation functions:
+       copyfuncs.c     - copy a node tree
+       equalfuncs.c    - compare two node trees
+       outfuncs.c      - convert a node tree to text representation
+       readfuncs.c     - convert text representation back to a node tree
+       makefuncs.c     - creator functions for some common node types
+       nodeFuncs.c     - some other general-purpose manipulation functions
+
+    Specialized manipulation functions:
+       bitmapset.c     - Bitmapset support
+       list.c          - generic list support
+       params.c        - Param support
+       tidbitmap.c     - TIDBitmap support
+       value.c         - support for Value nodes
+
+FILES IN src/include/nodes/
 
     Node definitions:
        nodes.h         - define node tags (NodeTag)
-       pg_list.h       - generic list 
        primnodes.h     - primitive nodes
        parsenodes.h    - parse tree nodes
        plannodes.h     - plan tree nodes
-       relation.h      - inner plan tree nodes
+       relation.h      - planner internal nodes
        execnodes.h     - executor nodes
        memnodes.h      - memory nodes
+       pg_list.h       - generic list 
 
 
 Steps to Add a Node
 -------------------
 
-Suppose you wana define a node Foo:
+Suppose you wanna define a node Foo:
 
-1. add a tag (T_Foo) to the enum NodeTag in nodes.h (You may have to
-   recompile the whole tree after doing this.)
-2. add the structure definition to the appropriate ???nodes.h file. If you
-   intend to inherit from, say a Plan node, put Plan as the first field of
-   you definition.
-3. if you intend to use copyObject, equal, nodeToString or stringToNode,
+1. Add a tag (T_Foo) to the enum NodeTag in nodes.h.  (If you insert the
+   tag in a way that moves the numbers associated with existing tags,
+   you'll need to recompile the whole tree after doing this.  It doesn't
+   force initdb though, because the numbers never go to disk.)
+2. Add the structure definition to the appropriate include/nodes/???.h file.
+   If you intend to inherit from, say a Plan node, put Plan as the first field
+   of your struct definition.
+3. If you intend to use copyObject, equal, nodeToString or stringToNode,
    add an appropriate function to copyfuncs.c, equalfuncs.c, outfuncs.c
-   and readfuncs.c accordingly. (Except for frequently used nodes, don't
-   bother writing a creator function in makefuncs.c)
+   and readfuncs.c accordingly.  (Except for frequently used nodes, don't
+   bother writing a creator function in makefuncs.c)  The header comments
+   in those files give general rules for whether you need to add support.
+4. Add cases to the functions in nodeFuncs.c as needed.  There are many
+   other places you'll probably also need to teach about your new node
+   type.  Best bet is to grep for references to one or two similar existing
+   node types to find all the places to touch.
 
 
 Historical Note
 ---------------
 
 Prior to the current simple C structure definitions, the Node structures 
-uses a pseudo-inheritance system which automatically generates creator and
-accessor functions. Since every node inherits from LispValue, the whole thing
-is a mess. Here's a little anecdote:
+used a pseudo-inheritance system which automatically generated creator and
+accessor functions. Since every node inherited from LispValue, the whole thing
+was a mess. Here's a little anecdote:
 
     LispValue definition -- class used to support lisp structures
     in C.  This is here because we did not want to totally rewrite
     planner and executor code which depended on lisp structures when
     we ported postgres V1 from lisp to C. -cim 4/23/90
index c72332a61127af3e45a8a94b1b5f3bd033ec9a02..7944936ba6edb567f08706ba66b107f624325a31 100644 (file)
 /*-------------------------------------------------------------------------
  *
  * nodeFuncs.c
- *       All node routines more complicated than simple access/modification
+ *             Various general-purpose manipulations of Node trees
  *
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.29 2008/01/01 19:45:50 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.30 2008/08/25 22:42:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
+#include "catalog/pg_type.h"
+#include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
+#include "nodes/relation.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
 
 
-static bool var_is_inner(Var *var);
+static bool expression_returns_set_walker(Node *node, void *context);
 
 
 /*
- * single_node -
- *       Returns t if node corresponds to a single-noded expression
+ *     exprType -
+ *       returns the Oid of the type of the expression. (Used for typechecking.)
+ */
+Oid
+exprType(Node *expr)
+{
+       Oid                     type;
+
+       if (!expr)
+               return InvalidOid;
+
+       switch (nodeTag(expr))
+       {
+               case T_Var:
+                       type = ((Var *) expr)->vartype;
+                       break;
+               case T_Const:
+                       type = ((Const *) expr)->consttype;
+                       break;
+               case T_Param:
+                       type = ((Param *) expr)->paramtype;
+                       break;
+               case T_Aggref:
+                       type = ((Aggref *) expr)->aggtype;
+                       break;
+               case T_ArrayRef:
+                       {
+                               ArrayRef   *arrayref = (ArrayRef *) expr;
+
+                               /* slice and/or store operations yield the array type */
+                               if (arrayref->reflowerindexpr || arrayref->refassgnexpr)
+                                       type = arrayref->refarraytype;
+                               else
+                                       type = arrayref->refelemtype;
+                       }
+                       break;
+               case T_FuncExpr:
+                       type = ((FuncExpr *) expr)->funcresulttype;
+                       break;
+               case T_OpExpr:
+                       type = ((OpExpr *) expr)->opresulttype;
+                       break;
+               case T_DistinctExpr:
+                       type = ((DistinctExpr *) expr)->opresulttype;
+                       break;
+               case T_ScalarArrayOpExpr:
+                       type = BOOLOID;
+                       break;
+               case T_BoolExpr:
+                       type = BOOLOID;
+                       break;
+               case T_SubLink:
+                       {
+                               SubLink    *sublink = (SubLink *) expr;
+
+                               if (sublink->subLinkType == EXPR_SUBLINK ||
+                                       sublink->subLinkType == ARRAY_SUBLINK)
+                               {
+                                       /* get the type of the subselect's first target column */
+                                       Query      *qtree = (Query *) sublink->subselect;
+                                       TargetEntry *tent;
+
+                                       if (!qtree || !IsA(qtree, Query))
+                                               elog(ERROR, "cannot get type for untransformed sublink");
+                                       tent = (TargetEntry *) linitial(qtree->targetList);
+                                       Assert(IsA(tent, TargetEntry));
+                                       Assert(!tent->resjunk);
+                                       type = exprType((Node *) tent->expr);
+                                       if (sublink->subLinkType == ARRAY_SUBLINK)
+                                       {
+                                               type = get_array_type(type);
+                                               if (!OidIsValid(type))
+                                                       ereport(ERROR,
+                                                                       (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                                                        errmsg("could not find array type for data type %s",
+                                                       format_type_be(exprType((Node *) tent->expr)))));
+                                       }
+                               }
+                               else
+                               {
+                                       /* for all other sublink types, result is boolean */
+                                       type = BOOLOID;
+                               }
+                       }
+                       break;
+               case T_SubPlan:
+                       {
+                               /*
+                                * Although the parser does not ever deal with already-planned
+                                * expression trees, we support SubPlan nodes in this routine
+                                * for the convenience of ruleutils.c.
+                                */
+                               SubPlan    *subplan = (SubPlan *) expr;
+
+                               if (subplan->subLinkType == EXPR_SUBLINK ||
+                                       subplan->subLinkType == ARRAY_SUBLINK)
+                               {
+                                       /* get the type of the subselect's first target column */
+                                       type = subplan->firstColType;
+                                       if (subplan->subLinkType == ARRAY_SUBLINK)
+                                       {
+                                               type = get_array_type(type);
+                                               if (!OidIsValid(type))
+                                                       ereport(ERROR,
+                                                                       (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                                                        errmsg("could not find array type for data type %s",
+                                                                       format_type_be(subplan->firstColType))));
+                                       }
+                               }
+                               else
+                               {
+                                       /* for all other subplan types, result is boolean */
+                                       type = BOOLOID;
+                               }
+                       }
+                       break;
+               case T_AlternativeSubPlan:
+                       {
+                               /* As above, supported for the convenience of ruleutils.c */
+                               AlternativeSubPlan *asplan = (AlternativeSubPlan *) expr;
+
+                               /* subplans should all return the same thing */
+                               type = exprType((Node *) linitial(asplan->subplans));
+                       }
+                       break;
+               case T_FieldSelect:
+                       type = ((FieldSelect *) expr)->resulttype;
+                       break;
+               case T_FieldStore:
+                       type = ((FieldStore *) expr)->resulttype;
+                       break;
+               case T_RelabelType:
+                       type = ((RelabelType *) expr)->resulttype;
+                       break;
+               case T_CoerceViaIO:
+                       type = ((CoerceViaIO *) expr)->resulttype;
+                       break;
+               case T_ArrayCoerceExpr:
+                       type = ((ArrayCoerceExpr *) expr)->resulttype;
+                       break;
+               case T_ConvertRowtypeExpr:
+                       type = ((ConvertRowtypeExpr *) expr)->resulttype;
+                       break;
+               case T_CaseExpr:
+                       type = ((CaseExpr *) expr)->casetype;
+                       break;
+               case T_CaseTestExpr:
+                       type = ((CaseTestExpr *) expr)->typeId;
+                       break;
+               case T_ArrayExpr:
+                       type = ((ArrayExpr *) expr)->array_typeid;
+                       break;
+               case T_RowExpr:
+                       type = ((RowExpr *) expr)->row_typeid;
+                       break;
+               case T_RowCompareExpr:
+                       type = BOOLOID;
+                       break;
+               case T_CoalesceExpr:
+                       type = ((CoalesceExpr *) expr)->coalescetype;
+                       break;
+               case T_MinMaxExpr:
+                       type = ((MinMaxExpr *) expr)->minmaxtype;
+                       break;
+               case T_XmlExpr:
+                       if (((XmlExpr *) expr)->op == IS_DOCUMENT)
+                               type = BOOLOID;
+                       else if (((XmlExpr *) expr)->op == IS_XMLSERIALIZE)
+                               type = TEXTOID;
+                       else
+                               type = XMLOID;
+                       break;
+               case T_NullIfExpr:
+                       type = exprType((Node *) linitial(((NullIfExpr *) expr)->args));
+                       break;
+               case T_NullTest:
+                       type = BOOLOID;
+                       break;
+               case T_BooleanTest:
+                       type = BOOLOID;
+                       break;
+               case T_CoerceToDomain:
+                       type = ((CoerceToDomain *) expr)->resulttype;
+                       break;
+               case T_CoerceToDomainValue:
+                       type = ((CoerceToDomainValue *) expr)->typeId;
+                       break;
+               case T_SetToDefault:
+                       type = ((SetToDefault *) expr)->typeId;
+                       break;
+               case T_CurrentOfExpr:
+                       type = BOOLOID;
+                       break;
+               default:
+                       elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
+                       type = InvalidOid;      /* keep compiler quiet */
+                       break;
+       }
+       return type;
+}
+
+/*
+ *     exprTypmod -
+ *       returns the type-specific attrmod of the expression, if it can be
+ *       determined.  In most cases, it can't and we return -1.
+ */
+int32
+exprTypmod(Node *expr)
+{
+       if (!expr)
+               return -1;
+
+       switch (nodeTag(expr))
+       {
+               case T_Var:
+                       return ((Var *) expr)->vartypmod;
+               case T_Const:
+                       return ((Const *) expr)->consttypmod;
+               case T_Param:
+                       return ((Param *) expr)->paramtypmod;
+               case T_ArrayRef:
+                       /* typmod is the same for array or element */
+                       return ((ArrayRef *) expr)->reftypmod;
+               case T_FuncExpr:
+                       {
+                               int32           coercedTypmod;
+
+                               /* Be smart about length-coercion functions... */
+                               if (exprIsLengthCoercion(expr, &coercedTypmod))
+                                       return coercedTypmod;
+                       }
+                       break;
+               case T_SubLink:
+                       {
+                               SubLink    *sublink = (SubLink *) expr;
+
+                               if (sublink->subLinkType == EXPR_SUBLINK ||
+                                       sublink->subLinkType == ARRAY_SUBLINK)
+                               {
+                                       /* get the typmod of the subselect's first target column */
+                                       Query      *qtree = (Query *) sublink->subselect;
+                                       TargetEntry *tent;
+
+                                       if (!qtree || !IsA(qtree, Query))
+                                               elog(ERROR, "cannot get type for untransformed sublink");
+                                       tent = (TargetEntry *) linitial(qtree->targetList);
+                                       Assert(IsA(tent, TargetEntry));
+                                       Assert(!tent->resjunk);
+                                       return exprTypmod((Node *) tent->expr);
+                                       /* note we don't need to care if it's an array */
+                               }
+                       }
+                       break;
+               case T_FieldSelect:
+                       return ((FieldSelect *) expr)->resulttypmod;
+               case T_RelabelType:
+                       return ((RelabelType *) expr)->resulttypmod;
+               case T_ArrayCoerceExpr:
+                       return ((ArrayCoerceExpr *) expr)->resulttypmod;
+               case T_CaseExpr:
+                       {
+                               /*
+                                * If all the alternatives agree on type/typmod, return that
+                                * typmod, else use -1
+                                */
+                               CaseExpr   *cexpr = (CaseExpr *) expr;
+                               Oid                     casetype = cexpr->casetype;
+                               int32           typmod;
+                               ListCell   *arg;
+
+                               if (!cexpr->defresult)
+                                       return -1;
+                               if (exprType((Node *) cexpr->defresult) != casetype)
+                                       return -1;
+                               typmod = exprTypmod((Node *) cexpr->defresult);
+                               if (typmod < 0)
+                                       return -1;      /* no point in trying harder */
+                               foreach(arg, cexpr->args)
+                               {
+                                       CaseWhen   *w = (CaseWhen *) lfirst(arg);
+
+                                       Assert(IsA(w, CaseWhen));
+                                       if (exprType((Node *) w->result) != casetype)
+                                               return -1;
+                                       if (exprTypmod((Node *) w->result) != typmod)
+                                               return -1;
+                               }
+                               return typmod;
+                       }
+                       break;
+               case T_CaseTestExpr:
+                       return ((CaseTestExpr *) expr)->typeMod;
+               case T_ArrayExpr:
+                       {
+                               /*
+                                * If all the elements agree on type/typmod, return that
+                                * typmod, else use -1
+                                */
+                               ArrayExpr  *arrayexpr = (ArrayExpr *) expr;
+                               Oid                     commontype;
+                               int32           typmod;
+                               ListCell   *elem;
+
+                               if (arrayexpr->elements == NIL)
+                                       return -1;
+                               typmod = exprTypmod((Node *) linitial(arrayexpr->elements));
+                               if (typmod < 0)
+                                       return -1;      /* no point in trying harder */
+                               if (arrayexpr->multidims)
+                                       commontype = arrayexpr->array_typeid;
+                               else
+                                       commontype = arrayexpr->element_typeid;
+                               foreach(elem, arrayexpr->elements)
+                               {
+                                       Node       *e = (Node *) lfirst(elem);
+
+                                       if (exprType(e) != commontype)
+                                               return -1;
+                                       if (exprTypmod(e) != typmod)
+                                               return -1;
+                               }
+                               return typmod;
+                       }
+                       break;
+               case T_CoalesceExpr:
+                       {
+                               /*
+                                * If all the alternatives agree on type/typmod, return that
+                                * typmod, else use -1
+                                */
+                               CoalesceExpr *cexpr = (CoalesceExpr *) expr;
+                               Oid                     coalescetype = cexpr->coalescetype;
+                               int32           typmod;
+                               ListCell   *arg;
+
+                               if (exprType((Node *) linitial(cexpr->args)) != coalescetype)
+                                       return -1;
+                               typmod = exprTypmod((Node *) linitial(cexpr->args));
+                               if (typmod < 0)
+                                       return -1;      /* no point in trying harder */
+                               for_each_cell(arg, lnext(list_head(cexpr->args)))
+                               {
+                                       Node       *e = (Node *) lfirst(arg);
+
+                                       if (exprType(e) != coalescetype)
+                                               return -1;
+                                       if (exprTypmod(e) != typmod)
+                                               return -1;
+                               }
+                               return typmod;
+                       }
+                       break;
+               case T_MinMaxExpr:
+                       {
+                               /*
+                                * If all the alternatives agree on type/typmod, return that
+                                * typmod, else use -1
+                                */
+                               MinMaxExpr *mexpr = (MinMaxExpr *) expr;
+                               Oid                     minmaxtype = mexpr->minmaxtype;
+                               int32           typmod;
+                               ListCell   *arg;
+
+                               if (exprType((Node *) linitial(mexpr->args)) != minmaxtype)
+                                       return -1;
+                               typmod = exprTypmod((Node *) linitial(mexpr->args));
+                               if (typmod < 0)
+                                       return -1;      /* no point in trying harder */
+                               for_each_cell(arg, lnext(list_head(mexpr->args)))
+                               {
+                                       Node       *e = (Node *) lfirst(arg);
+
+                                       if (exprType(e) != minmaxtype)
+                                               return -1;
+                                       if (exprTypmod(e) != typmod)
+                                               return -1;
+                               }
+                               return typmod;
+                       }
+                       break;
+               case T_NullIfExpr:
+                       {
+                               NullIfExpr *nexpr = (NullIfExpr *) expr;
+
+                               return exprTypmod((Node *) linitial(nexpr->args));
+                       }
+                       break;
+               case T_CoerceToDomain:
+                       return ((CoerceToDomain *) expr)->resulttypmod;
+               case T_CoerceToDomainValue:
+                       return ((CoerceToDomainValue *) expr)->typeMod;
+               case T_SetToDefault:
+                       return ((SetToDefault *) expr)->typeMod;
+               default:
+                       break;
+       }
+       return -1;
+}
+
+/*
+ * exprIsLengthCoercion
+ *             Detect whether an expression tree is an application of a datatype's
+ *             typmod-coercion function.  Optionally extract the result's typmod.
+ *
+ * If coercedTypmod is not NULL, the typmod is stored there if the expression
+ * is a length-coercion function, else -1 is stored there.
+ *
+ * Note that a combined type-and-length coercion will be treated as a
+ * length coercion by this routine.
  */
 bool
-single_node(Node *node)
+exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
 {
-       if (IsA(node, Const) ||
-               IsA(node, Var) ||
-               IsA(node, Param))
+       if (coercedTypmod != NULL)
+               *coercedTypmod = -1;    /* default result on failure */
+
+       /*
+        * Scalar-type length coercions are FuncExprs, array-type length coercions
+        * are ArrayCoerceExprs
+        */
+       if (expr && IsA(expr, FuncExpr))
+       {
+               FuncExpr   *func = (FuncExpr *) expr;
+               int                     nargs;
+               Const      *second_arg;
+
+               /*
+                * If it didn't come from a coercion context, reject.
+                */
+               if (func->funcformat != COERCE_EXPLICIT_CAST &&
+                       func->funcformat != COERCE_IMPLICIT_CAST)
+                       return false;
+
+               /*
+                * If it's not a two-argument or three-argument function with the
+                * second argument being an int4 constant, it can't have been created
+                * from a length coercion (it must be a type coercion, instead).
+                */
+               nargs = list_length(func->args);
+               if (nargs < 2 || nargs > 3)
+                       return false;
+
+               second_arg = (Const *) lsecond(func->args);
+               if (!IsA(second_arg, Const) ||
+                       second_arg->consttype != INT4OID ||
+                       second_arg->constisnull)
+                       return false;
+
+               /*
+                * OK, it is indeed a length-coercion function.
+                */
+               if (coercedTypmod != NULL)
+                       *coercedTypmod = DatumGetInt32(second_arg->constvalue);
+
                return true;
-       else
+       }
+
+       if (expr && IsA(expr, ArrayCoerceExpr))
+       {
+               ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) expr;
+
+               /* It's not a length coercion unless there's a nondefault typmod */
+               if (acoerce->resulttypmod < 0)
+                       return false;
+
+               /*
+                * OK, it is indeed a length-coercion expression.
+                */
+               if (coercedTypmod != NULL)
+                       *coercedTypmod = acoerce->resulttypmod;
+
+               return true;
+       }
+
+       return false;
+}
+
+/*
+ * expression_returns_set
+ *       Test whether an expression returns a set result.
+ *
+ * Because we use expression_tree_walker(), this can also be applied to
+ * whole targetlists; it'll produce TRUE if any one of the tlist items
+ * returns a set.
+ */
+bool
+expression_returns_set(Node *clause)
+{
+       return expression_returns_set_walker(clause, NULL);
+}
+
+static bool
+expression_returns_set_walker(Node *node, void *context)
+{
+       if (node == NULL)
                return false;
+       if (IsA(node, FuncExpr))
+       {
+               FuncExpr   *expr = (FuncExpr *) node;
+
+               if (expr->funcretset)
+                       return true;
+               /* else fall through to check args */
+       }
+       if (IsA(node, OpExpr))
+       {
+               OpExpr     *expr = (OpExpr *) node;
+
+               if (expr->opretset)
+                       return true;
+               /* else fall through to check args */
+       }
+
+       /* Avoid recursion for some cases that can't return a set */
+       if (IsA(node, Aggref))
+               return false;
+       if (IsA(node, DistinctExpr))
+               return false;
+       if (IsA(node, ScalarArrayOpExpr))
+               return false;
+       if (IsA(node, BoolExpr))
+               return false;
+       if (IsA(node, SubLink))
+               return false;
+       if (IsA(node, SubPlan))
+               return false;
+       if (IsA(node, AlternativeSubPlan))
+               return false;
+       if (IsA(node, ArrayExpr))
+               return false;
+       if (IsA(node, RowExpr))
+               return false;
+       if (IsA(node, RowCompareExpr))
+               return false;
+       if (IsA(node, CoalesceExpr))
+               return false;
+       if (IsA(node, MinMaxExpr))
+               return false;
+       if (IsA(node, XmlExpr))
+               return false;
+       if (IsA(node, NullIfExpr))
+               return false;
+
+       return expression_tree_walker(node, expression_returns_set_walker,
+                                                                 context);
 }
 
-/*****************************************************************************
- *             VAR nodes
- *****************************************************************************/
 
 /*
- *             var_is_outer
- *             var_is_inner
- *             var_is_mat
- *             var_is_rel
- *
- *             Returns t iff the var node corresponds to (respectively):
- *             the outer relation in a join
- *             the inner relation of a join
- *             a materialized relation
- *             a base relation (i.e., not an attribute reference, a variable from
- *                             some lower join level, or a sort result)
- *             var node is an array reference
+ * Standard expression-tree walking support
+ *
+ * We used to have near-duplicate code in many different routines that
+ * understood how to recurse through an expression node tree.  That was
+ * a pain to maintain, and we frequently had bugs due to some particular
+ * routine neglecting to support a particular node type.  In most cases,
+ * these routines only actually care about certain node types, and don't
+ * care about other types except insofar as they have to recurse through
+ * non-primitive node types.  Therefore, we now provide generic tree-walking
+ * logic to consolidate the redundant "boilerplate" code.  There are
+ * two versions: expression_tree_walker() and expression_tree_mutator().
+ */
+
+/*
+ * expression_tree_walker() is designed to support routines that traverse
+ * a tree in a read-only fashion (although it will also work for routines
+ * that modify nodes in-place but never add/delete/replace nodes).
+ * A walker routine should look like this:
+ *
+ * bool my_walker (Node *node, my_struct *context)
+ * {
+ *             if (node == NULL)
+ *                     return false;
+ *             // check for nodes that special work is required for, eg:
+ *             if (IsA(node, Var))
+ *             {
+ *                     ... do special actions for Var nodes
+ *             }
+ *             else if (IsA(node, ...))
+ *             {
+ *                     ... do special actions for other node types
+ *             }
+ *             // for any node type not specially processed, do:
+ *             return expression_tree_walker(node, my_walker, (void *) context);
+ * }
+ *
+ * The "context" argument points to a struct that holds whatever context
+ * information the walker routine needs --- it can be used to return data
+ * gathered by the walker, too.  This argument is not touched by
+ * expression_tree_walker, but it is passed down to recursive sub-invocations
+ * of my_walker.  The tree walk is started from a setup routine that
+ * fills in the appropriate context struct, calls my_walker with the top-level
+ * node of the tree, and then examines the results.
+ *
+ * The walker routine should return "false" to continue the tree walk, or
+ * "true" to abort the walk and immediately return "true" to the top-level
+ * caller.     This can be used to short-circuit the traversal if the walker
+ * has found what it came for. "false" is returned to the top-level caller
+ * iff no invocation of the walker returned "true".
+ *
+ * The node types handled by expression_tree_walker include all those
+ * normally found in target lists and qualifier clauses during the planning
+ * stage.  In particular, it handles List nodes since a cnf-ified qual clause
+ * will have List structure at the top level, and it handles TargetEntry nodes
+ * so that a scan of a target list can be handled without additional code.
+ * Also, RangeTblRef, FromExpr, JoinExpr, and SetOperationStmt nodes are
+ * handled, so that query jointrees and setOperation trees can be processed
+ * without additional code.
+ *
+ * expression_tree_walker will handle SubLink nodes by recursing normally
+ * into the "testexpr" subtree (which is an expression belonging to the outer
+ * plan).  It will also call the walker on the sub-Query node; however, when
+ * expression_tree_walker itself is called on a Query node, it does nothing
+ * and returns "false".  The net effect is that unless the walker does
+ * something special at a Query node, sub-selects will not be visited during
+ * an expression tree walk. This is exactly the behavior wanted in many cases
+ * --- and for those walkers that do want to recurse into sub-selects, special
+ * behavior is typically needed anyway at the entry to a sub-select (such as
+ * incrementing a depth counter). A walker that wants to examine sub-selects
+ * should include code along the lines of:
+ *
+ *             if (IsA(node, Query))
+ *             {
+ *                     adjust context for subquery;
+ *                     result = query_tree_walker((Query *) node, my_walker, context,
+ *                                                                        0); // adjust flags as needed
+ *                     restore context if needed;
+ *                     return result;
+ *             }
+ *
+ * query_tree_walker is a convenience routine (see below) that calls the
+ * walker on all the expression subtrees of the given Query node.
+ *
+ * expression_tree_walker will handle SubPlan nodes by recursing normally
+ * into the "testexpr" and the "args" list (which are expressions belonging to
+ * the outer plan).  It will not touch the completed subplan, however. Since
+ * there is no link to the original Query, it is not possible to recurse into
+ * subselects of an already-planned expression tree.  This is OK for current
+ * uses, but may need to be revisited in future.
+ */
+
+bool
+expression_tree_walker(Node *node,
+                                          bool (*walker) (),
+                                          void *context)
+{
+       ListCell   *temp;
+
+       /*
+        * The walker has already visited the current node, and so we need only
+        * recurse into any sub-nodes it has.
+        *
+        * We assume that the walker is not interested in List nodes per se, so
+        * when we expect a List we just recurse directly to self without
+        * bothering to call the walker.
+        */
+       if (node == NULL)
+               return false;
+
+       /* Guard against stack overflow due to overly complex expressions */
+       check_stack_depth();
+
+       switch (nodeTag(node))
+       {
+               case T_Var:
+               case T_Const:
+               case T_Param:
+               case T_CoerceToDomainValue:
+               case T_CaseTestExpr:
+               case T_SetToDefault:
+               case T_CurrentOfExpr:
+               case T_RangeTblRef:
+                       /* primitive node types with no expression subnodes */
+                       break;
+               case T_Aggref:
+                       {
+                               Aggref     *expr = (Aggref *) node;
+
+                               /* recurse directly on List */
+                               if (expression_tree_walker((Node *) expr->args,
+                                                                                  walker, context))
+                                       return true;
+                       }
+                       break;
+               case T_ArrayRef:
+                       {
+                               ArrayRef   *aref = (ArrayRef *) node;
+
+                               /* recurse directly for upper/lower array index lists */
+                               if (expression_tree_walker((Node *) aref->refupperindexpr,
+                                                                                  walker, context))
+                                       return true;
+                               if (expression_tree_walker((Node *) aref->reflowerindexpr,
+                                                                                  walker, context))
+                                       return true;
+                               /* walker must see the refexpr and refassgnexpr, however */
+                               if (walker(aref->refexpr, context))
+                                       return true;
+                               if (walker(aref->refassgnexpr, context))
+                                       return true;
+                       }
+                       break;
+               case T_FuncExpr:
+                       {
+                               FuncExpr   *expr = (FuncExpr *) node;
+
+                               if (expression_tree_walker((Node *) expr->args,
+                                                                                  walker, context))
+                                       return true;
+                       }
+                       break;
+               case T_OpExpr:
+                       {
+                               OpExpr     *expr = (OpExpr *) node;
+
+                               if (expression_tree_walker((Node *) expr->args,
+                                                                                  walker, context))
+                                       return true;
+                       }
+                       break;
+               case T_DistinctExpr:
+                       {
+                               DistinctExpr *expr = (DistinctExpr *) node;
+
+                               if (expression_tree_walker((Node *) expr->args,
+                                                                                  walker, context))
+                                       return true;
+                       }
+                       break;
+               case T_ScalarArrayOpExpr:
+                       {
+                               ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
+
+                               if (expression_tree_walker((Node *) expr->args,
+                                                                                  walker, context))
+                                       return true;
+                       }
+                       break;
+               case T_BoolExpr:
+                       {
+                               BoolExpr   *expr = (BoolExpr *) node;
+
+                               if (expression_tree_walker((Node *) expr->args,
+                                                                                  walker, context))
+                                       return true;
+                       }
+                       break;
+               case T_SubLink:
+                       {
+                               SubLink    *sublink = (SubLink *) node;
+
+                               if (walker(sublink->testexpr, context))
+                                       return true;
+
+                               /*
+                                * Also invoke the walker on the sublink's Query node, so it
+                                * can recurse into the sub-query if it wants to.
+                                */
+                               return walker(sublink->subselect, context);
+                       }
+                       break;
+               case T_SubPlan:
+                       {
+                               SubPlan    *subplan = (SubPlan *) node;
+
+                               /* recurse into the testexpr, but not into the Plan */
+                               if (walker(subplan->testexpr, context))
+                                       return true;
+                               /* also examine args list */
+                               if (expression_tree_walker((Node *) subplan->args,
+                                                                                  walker, context))
+                                       return true;
+                       }
+                       break;
+               case T_AlternativeSubPlan:
+                       return walker(((AlternativeSubPlan *) node)->subplans, context);
+               case T_FieldSelect:
+                       return walker(((FieldSelect *) node)->arg, context);
+               case T_FieldStore:
+                       {
+                               FieldStore *fstore = (FieldStore *) node;
+
+                               if (walker(fstore->arg, context))
+                                       return true;
+                               if (walker(fstore->newvals, context))
+                                       return true;
+                       }
+                       break;
+               case T_RelabelType:
+                       return walker(((RelabelType *) node)->arg, context);
+               case T_CoerceViaIO:
+                       return walker(((CoerceViaIO *) node)->arg, context);
+               case T_ArrayCoerceExpr:
+                       return walker(((ArrayCoerceExpr *) node)->arg, context);
+               case T_ConvertRowtypeExpr:
+                       return walker(((ConvertRowtypeExpr *) node)->arg, context);
+               case T_CaseExpr:
+                       {
+                               CaseExpr   *caseexpr = (CaseExpr *) node;
+
+                               if (walker(caseexpr->arg, context))
+                                       return true;
+                               /* we assume walker doesn't care about CaseWhens, either */
+                               foreach(temp, caseexpr->args)
+                               {
+                                       CaseWhen   *when = (CaseWhen *) lfirst(temp);
+
+                                       Assert(IsA(when, CaseWhen));
+                                       if (walker(when->expr, context))
+                                               return true;
+                                       if (walker(when->result, context))
+                                               return true;
+                               }
+                               if (walker(caseexpr->defresult, context))
+                                       return true;
+                       }
+                       break;
+               case T_ArrayExpr:
+                       return walker(((ArrayExpr *) node)->elements, context);
+               case T_RowExpr:
+                       return walker(((RowExpr *) node)->args, context);
+               case T_RowCompareExpr:
+                       {
+                               RowCompareExpr *rcexpr = (RowCompareExpr *) node;
+
+                               if (walker(rcexpr->largs, context))
+                                       return true;
+                               if (walker(rcexpr->rargs, context))
+                                       return true;
+                       }
+                       break;
+               case T_CoalesceExpr:
+                       return walker(((CoalesceExpr *) node)->args, context);
+               case T_MinMaxExpr:
+                       return walker(((MinMaxExpr *) node)->args, context);
+               case T_XmlExpr:
+                       {
+                               XmlExpr    *xexpr = (XmlExpr *) node;
+
+                               if (walker(xexpr->named_args, context))
+                                       return true;
+                               /* we assume walker doesn't care about arg_names */
+                               if (walker(xexpr->args, context))
+                                       return true;
+                       }
+                       break;
+               case T_NullIfExpr:
+                       return walker(((NullIfExpr *) node)->args, context);
+               case T_NullTest:
+                       return walker(((NullTest *) node)->arg, context);
+               case T_BooleanTest:
+                       return walker(((BooleanTest *) node)->arg, context);
+               case T_CoerceToDomain:
+                       return walker(((CoerceToDomain *) node)->arg, context);
+               case T_TargetEntry:
+                       return walker(((TargetEntry *) node)->expr, context);
+               case T_Query:
+                       /* Do nothing with a sub-Query, per discussion above */
+                       break;
+               case T_List:
+                       foreach(temp, (List *) node)
+                       {
+                               if (walker((Node *) lfirst(temp), context))
+                                       return true;
+                       }
+                       break;
+               case T_FromExpr:
+                       {
+                               FromExpr   *from = (FromExpr *) node;
+
+                               if (walker(from->fromlist, context))
+                                       return true;
+                               if (walker(from->quals, context))
+                                       return true;
+                       }
+                       break;
+               case T_JoinExpr:
+                       {
+                               JoinExpr   *join = (JoinExpr *) node;
+
+                               if (walker(join->larg, context))
+                                       return true;
+                               if (walker(join->rarg, context))
+                                       return true;
+                               if (walker(join->quals, context))
+                                       return true;
+
+                               /*
+                                * alias clause, using list are deemed uninteresting.
+                                */
+                       }
+                       break;
+               case T_SetOperationStmt:
+                       {
+                               SetOperationStmt *setop = (SetOperationStmt *) node;
+
+                               if (walker(setop->larg, context))
+                                       return true;
+                               if (walker(setop->rarg, context))
+                                       return true;
+
+                               /* groupClauses are deemed uninteresting */
+                       }
+                       break;
+               case T_FlattenedSubLink:
+                       {
+                               FlattenedSubLink *fslink = (FlattenedSubLink *) node;
+
+                               if (expression_tree_walker((Node *) fslink->quals,
+                                                                                  walker, context))
+                                       return true;
+                       }
+                       break;
+               case T_AppendRelInfo:
+                       {
+                               AppendRelInfo *appinfo = (AppendRelInfo *) node;
+
+                               if (expression_tree_walker((Node *) appinfo->translated_vars,
+                                                                                  walker, context))
+                                       return true;
+                       }
+                       break;
+               default:
+                       elog(ERROR, "unrecognized node type: %d",
+                                (int) nodeTag(node));
+                       break;
+       }
+       return false;
+}
+
+/*
+ * query_tree_walker --- initiate a walk of a Query's expressions
+ *
+ * This routine exists just to reduce the number of places that need to know
+ * where all the expression subtrees of a Query are.  Note it can be used
+ * for starting a walk at top level of a Query regardless of whether the
+ * walker intends to descend into subqueries.  It is also useful for
+ * descending into subqueries within a walker.
  *
+ * Some callers want to suppress visitation of certain items in the sub-Query,
+ * typically because they need to process them specially, or don't actually
+ * want to recurse into subqueries.  This is supported by the flags argument,
+ * which is the bitwise OR of flag values to suppress visitation of
+ * indicated items.  (More flag bits may be added as needed.)
  */
 bool
-var_is_outer(Var *var)
+query_tree_walker(Query *query,
+                                 bool (*walker) (),
+                                 void *context,
+                                 int flags)
 {
-       return (bool) (var->varno == OUTER);
+       Assert(query != NULL && IsA(query, Query));
+
+       if (walker((Node *) query->targetList, context))
+               return true;
+       if (walker((Node *) query->returningList, context))
+               return true;
+       if (walker((Node *) query->jointree, context))
+               return true;
+       if (walker(query->setOperations, context))
+               return true;
+       if (walker(query->havingQual, context))
+               return true;
+       if (walker(query->limitOffset, context))
+               return true;
+       if (walker(query->limitCount, context))
+               return true;
+       if (range_table_walker(query->rtable, walker, context, flags))
+               return true;
+       return false;
 }
 
-static bool
-var_is_inner(Var *var)
+/*
+ * range_table_walker is just the part of query_tree_walker that scans
+ * a query's rangetable.  This is split out since it can be useful on
+ * its own.
+ */
+bool
+range_table_walker(List *rtable,
+                                  bool (*walker) (),
+                                  void *context,
+                                  int flags)
 {
-       return (bool) (var->varno == INNER);
+       ListCell   *rt;
+
+       foreach(rt, rtable)
+       {
+               RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
+
+               switch (rte->rtekind)
+               {
+                       case RTE_RELATION:
+                       case RTE_SPECIAL:
+                               /* nothing to do */
+                               break;
+                       case RTE_SUBQUERY:
+                               if (!(flags & QTW_IGNORE_RT_SUBQUERIES))
+                                       if (walker(rte->subquery, context))
+                                               return true;
+                               break;
+                       case RTE_JOIN:
+                               if (!(flags & QTW_IGNORE_JOINALIASES))
+                                       if (walker(rte->joinaliasvars, context))
+                                               return true;
+                               break;
+                       case RTE_FUNCTION:
+                               if (walker(rte->funcexpr, context))
+                                       return true;
+                               break;
+                       case RTE_VALUES:
+                               if (walker(rte->values_lists, context))
+                                       return true;
+                               break;
+               }
+       }
+       return false;
 }
 
+
+/*
+ * expression_tree_mutator() is designed to support routines that make a
+ * modified copy of an expression tree, with some nodes being added,
+ * removed, or replaced by new subtrees.  The original tree is (normally)
+ * not changed.  Each recursion level is responsible for returning a copy of
+ * (or appropriately modified substitute for) the subtree it is handed.
+ * A mutator routine should look like this:
+ *
+ * Node * my_mutator (Node *node, my_struct *context)
+ * {
+ *             if (node == NULL)
+ *                     return NULL;
+ *             // check for nodes that special work is required for, eg:
+ *             if (IsA(node, Var))
+ *             {
+ *                     ... create and return modified copy of Var node
+ *             }
+ *             else if (IsA(node, ...))
+ *             {
+ *                     ... do special transformations of other node types
+ *             }
+ *             // for any node type not specially processed, do:
+ *             return expression_tree_mutator(node, my_mutator, (void *) context);
+ * }
+ *
+ * The "context" argument points to a struct that holds whatever context
+ * information the mutator routine needs --- it can be used to return extra
+ * data gathered by the mutator, too.  This argument is not touched by
+ * expression_tree_mutator, but it is passed down to recursive sub-invocations
+ * of my_mutator.  The tree walk is started from a setup routine that
+ * fills in the appropriate context struct, calls my_mutator with the
+ * top-level node of the tree, and does any required post-processing.
+ *
+ * Each level of recursion must return an appropriately modified Node.
+ * If expression_tree_mutator() is called, it will make an exact copy
+ * of the given Node, but invoke my_mutator() to copy the sub-node(s)
+ * of that Node.  In this way, my_mutator() has full control over the
+ * copying process but need not directly deal with expression trees
+ * that it has no interest in.
+ *
+ * Just as for expression_tree_walker, the node types handled by
+ * expression_tree_mutator include all those normally found in target lists
+ * and qualifier clauses during the planning stage.
+ *
+ * expression_tree_mutator will handle SubLink nodes by recursing normally
+ * into the "testexpr" subtree (which is an expression belonging to the outer
+ * plan).  It will also call the mutator on the sub-Query node; however, when
+ * expression_tree_mutator itself is called on a Query node, it does nothing
+ * and returns the unmodified Query node.  The net effect is that unless the
+ * mutator does something special at a Query node, sub-selects will not be
+ * visited or modified; the original sub-select will be linked to by the new
+ * SubLink node.  Mutators that want to descend into sub-selects will usually
+ * do so by recognizing Query nodes and calling query_tree_mutator (below).
+ *
+ * expression_tree_mutator will handle a SubPlan node by recursing into the
+ * "testexpr" and the "args" list (which belong to the outer plan), but it
+ * will simply copy the link to the inner plan, since that's typically what
+ * expression tree mutators want.  A mutator that wants to modify the subplan
+ * can force appropriate behavior by recognizing SubPlan expression nodes
+ * and doing the right thing.
+ */
+
+Node *
+expression_tree_mutator(Node *node,
+                                               Node *(*mutator) (),
+                                               void *context)
+{
+       /*
+        * The mutator has already decided not to modify the current node, but we
+        * must call the mutator for any sub-nodes.
+        */
+
+#define FLATCOPY(newnode, node, nodetype)  \
+       ( (newnode) = (nodetype *) palloc(sizeof(nodetype)), \
+         memcpy((newnode), (node), sizeof(nodetype)) )
+
+#define CHECKFLATCOPY(newnode, node, nodetype) \
+       ( AssertMacro(IsA((node), nodetype)), \
+         (newnode) = (nodetype *) palloc(sizeof(nodetype)), \
+         memcpy((newnode), (node), sizeof(nodetype)) )
+
+#define MUTATE(newfield, oldfield, fieldtype)  \
+               ( (newfield) = (fieldtype) mutator((Node *) (oldfield), context) )
+
+       if (node == NULL)
+               return NULL;
+
+       /* Guard against stack overflow due to overly complex expressions */
+       check_stack_depth();
+
+       switch (nodeTag(node))
+       {
+                       /*
+                        * Primitive node types with no expression subnodes.  Var and
+                        * Const are frequent enough to deserve special cases, the others
+                        * we just use copyObject for.
+                        */
+               case T_Var:
+                       {
+                               Var                *var = (Var *) node;
+                               Var                *newnode;
+
+                               FLATCOPY(newnode, var, Var);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_Const:
+                       {
+                               Const      *oldnode = (Const *) node;
+                               Const      *newnode;
+
+                               FLATCOPY(newnode, oldnode, Const);
+                               /* XXX we don't bother with datumCopy; should we? */
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_Param:
+               case T_CoerceToDomainValue:
+               case T_CaseTestExpr:
+               case T_SetToDefault:
+               case T_CurrentOfExpr:
+               case T_RangeTblRef:
+                       return (Node *) copyObject(node);
+               case T_Aggref:
+                       {
+                               Aggref     *aggref = (Aggref *) node;
+                               Aggref     *newnode;
+
+                               FLATCOPY(newnode, aggref, Aggref);
+                               MUTATE(newnode->args, aggref->args, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_ArrayRef:
+                       {
+                               ArrayRef   *arrayref = (ArrayRef *) node;
+                               ArrayRef   *newnode;
+
+                               FLATCOPY(newnode, arrayref, ArrayRef);
+                               MUTATE(newnode->refupperindexpr, arrayref->refupperindexpr,
+                                          List *);
+                               MUTATE(newnode->reflowerindexpr, arrayref->reflowerindexpr,
+                                          List *);
+                               MUTATE(newnode->refexpr, arrayref->refexpr,
+                                          Expr *);
+                               MUTATE(newnode->refassgnexpr, arrayref->refassgnexpr,
+                                          Expr *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_FuncExpr:
+                       {
+                               FuncExpr   *expr = (FuncExpr *) node;
+                               FuncExpr   *newnode;
+
+                               FLATCOPY(newnode, expr, FuncExpr);
+                               MUTATE(newnode->args, expr->args, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_OpExpr:
+                       {
+                               OpExpr     *expr = (OpExpr *) node;
+                               OpExpr     *newnode;
+
+                               FLATCOPY(newnode, expr, OpExpr);
+                               MUTATE(newnode->args, expr->args, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_DistinctExpr:
+                       {
+                               DistinctExpr *expr = (DistinctExpr *) node;
+                               DistinctExpr *newnode;
+
+                               FLATCOPY(newnode, expr, DistinctExpr);
+                               MUTATE(newnode->args, expr->args, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_ScalarArrayOpExpr:
+                       {
+                               ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
+                               ScalarArrayOpExpr *newnode;
+
+                               FLATCOPY(newnode, expr, ScalarArrayOpExpr);
+                               MUTATE(newnode->args, expr->args, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_BoolExpr:
+                       {
+                               BoolExpr   *expr = (BoolExpr *) node;
+                               BoolExpr   *newnode;
+
+                               FLATCOPY(newnode, expr, BoolExpr);
+                               MUTATE(newnode->args, expr->args, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_SubLink:
+                       {
+                               SubLink    *sublink = (SubLink *) node;
+                               SubLink    *newnode;
+
+                               FLATCOPY(newnode, sublink, SubLink);
+                               MUTATE(newnode->testexpr, sublink->testexpr, Node *);
+
+                               /*
+                                * Also invoke the mutator on the sublink's Query node, so it
+                                * can recurse into the sub-query if it wants to.
+                                */
+                               MUTATE(newnode->subselect, sublink->subselect, Node *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_SubPlan:
+                       {
+                               SubPlan    *subplan = (SubPlan *) node;
+                               SubPlan    *newnode;
+
+                               FLATCOPY(newnode, subplan, SubPlan);
+                               /* transform testexpr */
+                               MUTATE(newnode->testexpr, subplan->testexpr, Node *);
+                               /* transform args list (params to be passed to subplan) */
+                               MUTATE(newnode->args, subplan->args, List *);
+                               /* but not the sub-Plan itself, which is referenced as-is */
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_AlternativeSubPlan:
+                       {
+                               AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
+                               AlternativeSubPlan *newnode;
+
+                               FLATCOPY(newnode, asplan, AlternativeSubPlan);
+                               MUTATE(newnode->subplans, asplan->subplans, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_FieldSelect:
+                       {
+                               FieldSelect *fselect = (FieldSelect *) node;
+                               FieldSelect *newnode;
+
+                               FLATCOPY(newnode, fselect, FieldSelect);
+                               MUTATE(newnode->arg, fselect->arg, Expr *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_FieldStore:
+                       {
+                               FieldStore *fstore = (FieldStore *) node;
+                               FieldStore *newnode;
+
+                               FLATCOPY(newnode, fstore, FieldStore);
+                               MUTATE(newnode->arg, fstore->arg, Expr *);
+                               MUTATE(newnode->newvals, fstore->newvals, List *);
+                               newnode->fieldnums = list_copy(fstore->fieldnums);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_RelabelType:
+                       {
+                               RelabelType *relabel = (RelabelType *) node;
+                               RelabelType *newnode;
+
+                               FLATCOPY(newnode, relabel, RelabelType);
+                               MUTATE(newnode->arg, relabel->arg, Expr *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_CoerceViaIO:
+                       {
+                               CoerceViaIO *iocoerce = (CoerceViaIO *) node;
+                               CoerceViaIO *newnode;
+
+                               FLATCOPY(newnode, iocoerce, CoerceViaIO);
+                               MUTATE(newnode->arg, iocoerce->arg, Expr *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_ArrayCoerceExpr:
+                       {
+                               ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
+                               ArrayCoerceExpr *newnode;
+
+                               FLATCOPY(newnode, acoerce, ArrayCoerceExpr);
+                               MUTATE(newnode->arg, acoerce->arg, Expr *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_ConvertRowtypeExpr:
+                       {
+                               ConvertRowtypeExpr *convexpr = (ConvertRowtypeExpr *) node;
+                               ConvertRowtypeExpr *newnode;
+
+                               FLATCOPY(newnode, convexpr, ConvertRowtypeExpr);
+                               MUTATE(newnode->arg, convexpr->arg, Expr *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_CaseExpr:
+                       {
+                               CaseExpr   *caseexpr = (CaseExpr *) node;
+                               CaseExpr   *newnode;
+
+                               FLATCOPY(newnode, caseexpr, CaseExpr);
+                               MUTATE(newnode->arg, caseexpr->arg, Expr *);
+                               MUTATE(newnode->args, caseexpr->args, List *);
+                               MUTATE(newnode->defresult, caseexpr->defresult, Expr *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_CaseWhen:
+                       {
+                               CaseWhen   *casewhen = (CaseWhen *) node;
+                               CaseWhen   *newnode;
+
+                               FLATCOPY(newnode, casewhen, CaseWhen);
+                               MUTATE(newnode->expr, casewhen->expr, Expr *);
+                               MUTATE(newnode->result, casewhen->result, Expr *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_ArrayExpr:
+                       {
+                               ArrayExpr  *arrayexpr = (ArrayExpr *) node;
+                               ArrayExpr  *newnode;
+
+                               FLATCOPY(newnode, arrayexpr, ArrayExpr);
+                               MUTATE(newnode->elements, arrayexpr->elements, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_RowExpr:
+                       {
+                               RowExpr    *rowexpr = (RowExpr *) node;
+                               RowExpr    *newnode;
+
+                               FLATCOPY(newnode, rowexpr, RowExpr);
+                               MUTATE(newnode->args, rowexpr->args, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_RowCompareExpr:
+                       {
+                               RowCompareExpr *rcexpr = (RowCompareExpr *) node;
+                               RowCompareExpr *newnode;
+
+                               FLATCOPY(newnode, rcexpr, RowCompareExpr);
+                               MUTATE(newnode->largs, rcexpr->largs, List *);
+                               MUTATE(newnode->rargs, rcexpr->rargs, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_CoalesceExpr:
+                       {
+                               CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
+                               CoalesceExpr *newnode;
+
+                               FLATCOPY(newnode, coalesceexpr, CoalesceExpr);
+                               MUTATE(newnode->args, coalesceexpr->args, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_MinMaxExpr:
+                       {
+                               MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
+                               MinMaxExpr *newnode;
+
+                               FLATCOPY(newnode, minmaxexpr, MinMaxExpr);
+                               MUTATE(newnode->args, minmaxexpr->args, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_XmlExpr:
+                       {
+                               XmlExpr    *xexpr = (XmlExpr *) node;
+                               XmlExpr    *newnode;
+
+                               FLATCOPY(newnode, xexpr, XmlExpr);
+                               MUTATE(newnode->named_args, xexpr->named_args, List *);
+                               /* assume mutator does not care about arg_names */
+                               MUTATE(newnode->args, xexpr->args, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_NullIfExpr:
+                       {
+                               NullIfExpr *expr = (NullIfExpr *) node;
+                               NullIfExpr *newnode;
+
+                               FLATCOPY(newnode, expr, NullIfExpr);
+                               MUTATE(newnode->args, expr->args, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_NullTest:
+                       {
+                               NullTest   *ntest = (NullTest *) node;
+                               NullTest   *newnode;
+
+                               FLATCOPY(newnode, ntest, NullTest);
+                               MUTATE(newnode->arg, ntest->arg, Expr *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_BooleanTest:
+                       {
+                               BooleanTest *btest = (BooleanTest *) node;
+                               BooleanTest *newnode;
+
+                               FLATCOPY(newnode, btest, BooleanTest);
+                               MUTATE(newnode->arg, btest->arg, Expr *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_CoerceToDomain:
+                       {
+                               CoerceToDomain *ctest = (CoerceToDomain *) node;
+                               CoerceToDomain *newnode;
+
+                               FLATCOPY(newnode, ctest, CoerceToDomain);
+                               MUTATE(newnode->arg, ctest->arg, Expr *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_TargetEntry:
+                       {
+                               TargetEntry *targetentry = (TargetEntry *) node;
+                               TargetEntry *newnode;
+
+                               FLATCOPY(newnode, targetentry, TargetEntry);
+                               MUTATE(newnode->expr, targetentry->expr, Expr *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_Query:
+                       /* Do nothing with a sub-Query, per discussion above */
+                       return node;
+               case T_List:
+                       {
+                               /*
+                                * We assume the mutator isn't interested in the list nodes
+                                * per se, so just invoke it on each list element. NOTE: this
+                                * would fail badly on a list with integer elements!
+                                */
+                               List       *resultlist;
+                               ListCell   *temp;
+
+                               resultlist = NIL;
+                               foreach(temp, (List *) node)
+                               {
+                                       resultlist = lappend(resultlist,
+                                                                                mutator((Node *) lfirst(temp),
+                                                                                                context));
+                               }
+                               return (Node *) resultlist;
+                       }
+                       break;
+               case T_FromExpr:
+                       {
+                               FromExpr   *from = (FromExpr *) node;
+                               FromExpr   *newnode;
+
+                               FLATCOPY(newnode, from, FromExpr);
+                               MUTATE(newnode->fromlist, from->fromlist, List *);
+                               MUTATE(newnode->quals, from->quals, Node *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_JoinExpr:
+                       {
+                               JoinExpr   *join = (JoinExpr *) node;
+                               JoinExpr   *newnode;
+
+                               FLATCOPY(newnode, join, JoinExpr);
+                               MUTATE(newnode->larg, join->larg, Node *);
+                               MUTATE(newnode->rarg, join->rarg, Node *);
+                               MUTATE(newnode->quals, join->quals, Node *);
+                               /* We do not mutate alias or using by default */
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_SetOperationStmt:
+                       {
+                               SetOperationStmt *setop = (SetOperationStmt *) node;
+                               SetOperationStmt *newnode;
+
+                               FLATCOPY(newnode, setop, SetOperationStmt);
+                               MUTATE(newnode->larg, setop->larg, Node *);
+                               MUTATE(newnode->rarg, setop->rarg, Node *);
+                               /* We do not mutate groupClauses by default */
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_FlattenedSubLink:
+                       {
+                               FlattenedSubLink *fslink = (FlattenedSubLink *) node;
+                               FlattenedSubLink *newnode;
+
+                               FLATCOPY(newnode, fslink, FlattenedSubLink);
+                               /* Assume we need not copy the relids bitmapsets */
+                               MUTATE(newnode->quals, fslink->quals, Expr *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_AppendRelInfo:
+                       {
+                               AppendRelInfo *appinfo = (AppendRelInfo *) node;
+                               AppendRelInfo *newnode;
+
+                               FLATCOPY(newnode, appinfo, AppendRelInfo);
+                               MUTATE(newnode->translated_vars, appinfo->translated_vars, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               default:
+                       elog(ERROR, "unrecognized node type: %d",
+                                (int) nodeTag(node));
+                       break;
+       }
+       /* can't get here, but keep compiler happy */
+       return NULL;
+}
+
+
+/*
+ * query_tree_mutator --- initiate modification of a Query's expressions
+ *
+ * This routine exists just to reduce the number of places that need to know
+ * where all the expression subtrees of a Query are.  Note it can be used
+ * for starting a walk at top level of a Query regardless of whether the
+ * mutator intends to descend into subqueries. It is also useful for
+ * descending into subqueries within a mutator.
+ *
+ * Some callers want to suppress mutating of certain items in the Query,
+ * typically because they need to process them specially, or don't actually
+ * want to recurse into subqueries.  This is supported by the flags argument,
+ * which is the bitwise OR of flag values to suppress mutating of
+ * indicated items.  (More flag bits may be added as needed.)
+ *
+ * Normally the Query node itself is copied, but some callers want it to be
+ * modified in-place; they must pass QTW_DONT_COPY_QUERY in flags.     All
+ * modified substructure is safely copied in any case.
+ */
+Query *
+query_tree_mutator(Query *query,
+                                  Node *(*mutator) (),
+                                  void *context,
+                                  int flags)
+{
+       Assert(query != NULL && IsA(query, Query));
+
+       if (!(flags & QTW_DONT_COPY_QUERY))
+       {
+               Query      *newquery;
+
+               FLATCOPY(newquery, query, Query);
+               query = newquery;
+       }
+
+       MUTATE(query->targetList, query->targetList, List *);
+       MUTATE(query->returningList, query->returningList, List *);
+       MUTATE(query->jointree, query->jointree, FromExpr *);
+       MUTATE(query->setOperations, query->setOperations, Node *);
+       MUTATE(query->havingQual, query->havingQual, Node *);
+       MUTATE(query->limitOffset, query->limitOffset, Node *);
+       MUTATE(query->limitCount, query->limitCount, Node *);
+       query->rtable = range_table_mutator(query->rtable,
+                                                                               mutator, context, flags);
+       return query;
+}
+
+/*
+ * range_table_mutator is just the part of query_tree_mutator that processes
+ * a query's rangetable.  This is split out since it can be useful on
+ * its own.
+ */
+List *
+range_table_mutator(List *rtable,
+                                       Node *(*mutator) (),
+                                       void *context,
+                                       int flags)
+{
+       List       *newrt = NIL;
+       ListCell   *rt;
+
+       foreach(rt, rtable)
+       {
+               RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
+               RangeTblEntry *newrte;
+
+               FLATCOPY(newrte, rte, RangeTblEntry);
+               switch (rte->rtekind)
+               {
+                       case RTE_RELATION:
+                       case RTE_SPECIAL:
+                               /* we don't bother to copy eref, aliases, etc; OK? */
+                               break;
+                       case RTE_SUBQUERY:
+                               if (!(flags & QTW_IGNORE_RT_SUBQUERIES))
+                               {
+                                       CHECKFLATCOPY(newrte->subquery, rte->subquery, Query);
+                                       MUTATE(newrte->subquery, newrte->subquery, Query *);
+                               }
+                               else
+                               {
+                                       /* else, copy RT subqueries as-is */
+                                       newrte->subquery = copyObject(rte->subquery);
+                               }
+                               break;
+                       case RTE_JOIN:
+                               if (!(flags & QTW_IGNORE_JOINALIASES))
+                                       MUTATE(newrte->joinaliasvars, rte->joinaliasvars, List *);
+                               else
+                               {
+                                       /* else, copy join aliases as-is */
+                                       newrte->joinaliasvars = copyObject(rte->joinaliasvars);
+                               }
+                               break;
+                       case RTE_FUNCTION:
+                               MUTATE(newrte->funcexpr, rte->funcexpr, Node *);
+                               break;
+                       case RTE_VALUES:
+                               MUTATE(newrte->values_lists, rte->values_lists, List *);
+                               break;
+               }
+               newrt = lappend(newrt, newrte);
+       }
+       return newrt;
+}
+
+/*
+ * query_or_expression_tree_walker --- hybrid form
+ *
+ * This routine will invoke query_tree_walker if called on a Query node,
+ * else will invoke the walker directly.  This is a useful way of starting
+ * the recursion when the walker's normal change of state is not appropriate
+ * for the outermost Query node.
+ */
 bool
-var_is_rel(Var *var)
+query_or_expression_tree_walker(Node *node,
+                                                               bool (*walker) (),
+                                                               void *context,
+                                                               int flags)
 {
-       return (bool)
-               !(var_is_inner(var) || var_is_outer(var));
+       if (node && IsA(node, Query))
+               return query_tree_walker((Query *) node,
+                                                                walker,
+                                                                context,
+                                                                flags);
+       else
+               return walker(node, context);
+}
+
+/*
+ * query_or_expression_tree_mutator --- hybrid form
+ *
+ * This routine will invoke query_tree_mutator if called on a Query node,
+ * else will invoke the mutator directly.  This is a useful way of starting
+ * the recursion when the mutator's normal change of state is not appropriate
+ * for the outermost Query node.
+ */
+Node *
+query_or_expression_tree_mutator(Node *node,
+                                                                Node *(*mutator) (),
+                                                                void *context,
+                                                                int flags)
+{
+       if (node && IsA(node, Query))
+               return (Node *) query_tree_mutator((Query *) node,
+                                                                                  mutator,
+                                                                                  context,
+                                                                                  flags);
+       else
+               return mutator(node, context);
 }
index b13371e00eb959f98d1720f27a17ad9a3e0136f9..3dc41c6807323e1836a3d333384f4ffe0fd051fa 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.172 2008/08/02 21:31:59 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.173 2008/08/25 22:42:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,6 +17,7 @@
 
 #include <math.h>
 
+#include "nodes/nodeFuncs.h"
 #ifdef OPTIMIZER_DEBUG
 #include "nodes/print.h"
 #endif
@@ -30,7 +31,6 @@
 #include "optimizer/prep.h"
 #include "optimizer/var.h"
 #include "parser/parse_clause.h"
-#include "parser/parse_expr.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteManip.h"
 
index 487de9ee934409894f25cabe188f81455464c782..49f81845c927248af12e735e4d3555bcd2e905b6 100644 (file)
@@ -54,7 +54,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.195 2008/08/22 00:16:03 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.196 2008/08/25 22:42:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "executor/nodeHash.h"
 #include "miscadmin.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/planmain.h"
 #include "parser/parsetree.h"
-#include "parser/parse_expr.h"
 #include "utils/lsyscache.h"
 #include "utils/selfuncs.h"
 #include "utils/tuplesort.h"
index c4459e6e3eb2d4d01e301c09e9203c54620ee5a8..0847b95574a58972f3157949f4eff58e865bf6b0 100644 (file)
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.11 2008/08/02 21:31:59 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.12 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/skey.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
 #include "optimizer/paths.h"
index ccb23834de009d938735b210da6a191366762bda..c68785108ab76f9c34db138816a298a08aed7143 100644 (file)
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.94 2008/08/02 21:31:59 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.95 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "access/skey.h"
 #include "catalog/pg_type.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "nodes/plannodes.h"
 #include "optimizer/clauses.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
-#include "parser/parse_expr.h"
 #include "utils/lsyscache.h"
 
 
index 3def7c3738b35124a509076b7532b9c04f38652c..7eada8d90825c9bdfd809df883a0521e570ec562 100644 (file)
@@ -30,7 +30,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/tidpath.c,v 1.32 2008/05/12 00:00:49 alvherre Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/tidpath.c,v 1.33 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "access/sysattr.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_type.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
-#include "parser/parse_expr.h"
 
 
 static bool IsTidEqualClause(OpExpr *node, int varno);
index ea85fe016e46ba150f09406dffb5f58d9b693ad6..a0ca92bd73dfe96afe8f5401948110b67c15b708 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.245 2008/08/14 18:47:59 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.246 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,7 @@
 
 #include "access/skey.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
 #include "optimizer/plancat.h"
@@ -30,7 +31,6 @@
 #include "optimizer/tlist.h"
 #include "optimizer/var.h"
 #include "parser/parse_clause.h"
-#include "parser/parse_expr.h"
 #include "parser/parsetree.h"
 #include "utils/lsyscache.h"
 
index a6b4b1df661620e494148fc9bf7ff62c0bcaa3e5..8a6b2ad0345e7fab630bd0efb131b0714bd8381c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.42 2008/08/02 21:32:00 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.43 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 #include "catalog/pg_am.h"
 #include "catalog/pg_type.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
 #include "optimizer/pathnode.h"
@@ -26,7 +27,6 @@
 #include "optimizer/predtest.h"
 #include "optimizer/subselect.h"
 #include "parser/parse_clause.h"
-#include "parser/parse_expr.h"
 #include "parser/parsetree.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
index 7bcbabd1010dff891776b3eb9a8dd77405fb5029..b9d5643da8aa6c16007835380330205abdc9cb75 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.142 2008/06/17 14:51:32 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.143 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "catalog/pg_type.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/planmain.h"
 #include "optimizer/tlist.h"
-#include "parser/parse_expr.h"
 #include "parser/parsetree.h"
 #include "utils/lsyscache.h"
 
index ee2d936b3494c081c759b2176af6a40de4aca669..42ac74e1a25baf87dea536f489dba327491ae492 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.138 2008/08/22 00:16:04 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.139 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,6 +17,7 @@
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
 #include "optimizer/planmain.h"
@@ -24,7 +25,6 @@
 #include "optimizer/prep.h"
 #include "optimizer/subselect.h"
 #include "optimizer/var.h"
-#include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteManip.h"
index 24e9fdb0b0aab7e74803c9b21eceb7e8d80581a0..965856385d77a2fae252284e2a04470d930819fe 100644 (file)
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.53 2008/08/17 01:20:00 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.54 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/prep.h"
 #include "optimizer/subselect.h"
 #include "optimizer/tlist.h"
 #include "optimizer/var.h"
-#include "parser/parse_expr.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteManip.h"
 
index 2fcdf0592fc3a56f7b0062052b3a8a1f3d3ca24e..c07ca4434a30838c606e58c7f55c6926e0a486d6 100644 (file)
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.153 2008/08/14 18:47:59 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.154 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,7 +34,7 @@
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
-#include "optimizer/clauses.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/cost.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
@@ -45,7 +45,6 @@
 #include "optimizer/tlist.h"
 #include "parser/parse_clause.h"
 #include "parser/parse_coerce.h"
-#include "parser/parse_expr.h"
 #include "parser/parsetree.h"
 #include "utils/lsyscache.h"
 #include "utils/rel.h"
index 6a06b0806c27440c63e87c6111dcb0f0674fdc87..c015be9e9bf77ef70a3bbed795d497f834c93c8b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.263 2008/08/22 00:16:04 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.264 2008/08/25 22:42:33 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
 #include "executor/functions.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
 #include "optimizer/planmain.h"
-#include "optimizer/planner.h"
 #include "optimizer/prep.h"
 #include "optimizer/var.h"
 #include "parser/analyze.h"
-#include "parser/parse_clause.h"
 #include "parser/parse_coerce.h"
-#include "parser/parse_expr.h"
 #include "rewrite/rewriteManip.h"
 #include "tcop/tcopprot.h"
 #include "utils/acl.h"
@@ -73,7 +71,6 @@ typedef struct
 
 static bool contain_agg_clause_walker(Node *node, void *context);
 static bool count_agg_clauses_walker(Node *node, AggClauseCounts *counts);
-static bool expression_returns_set_walker(Node *node, void *context);
 static bool expression_returns_set_rows_walker(Node *node, double *count);
 static bool contain_subplans_walker(Node *node, void *context);
 static bool contain_mutable_functions_walker(Node *node, void *context);
@@ -517,82 +514,14 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts)
  *             Support for expressions returning sets
  *****************************************************************************/
 
-/*
- * expression_returns_set
- *       Test whether an expression returns a set result.
- *
- * Because we use expression_tree_walker(), this can also be applied to
- * whole targetlists; it'll produce TRUE if any one of the tlist items
- * returns a set.
- */
-bool
-expression_returns_set(Node *clause)
-{
-       return expression_returns_set_walker(clause, NULL);
-}
-
-static bool
-expression_returns_set_walker(Node *node, void *context)
-{
-       if (node == NULL)
-               return false;
-       if (IsA(node, FuncExpr))
-       {
-               FuncExpr   *expr = (FuncExpr *) node;
-
-               if (expr->funcretset)
-                       return true;
-               /* else fall through to check args */
-       }
-       if (IsA(node, OpExpr))
-       {
-               OpExpr     *expr = (OpExpr *) node;
-
-               if (expr->opretset)
-                       return true;
-               /* else fall through to check args */
-       }
-
-       /* Avoid recursion for some cases that can't return a set */
-       if (IsA(node, Aggref))
-               return false;
-       if (IsA(node, DistinctExpr))
-               return false;
-       if (IsA(node, ScalarArrayOpExpr))
-               return false;
-       if (IsA(node, BoolExpr))
-               return false;
-       if (IsA(node, SubLink))
-               return false;
-       if (IsA(node, SubPlan))
-               return false;
-       if (IsA(node, AlternativeSubPlan))
-               return false;
-       if (IsA(node, ArrayExpr))
-               return false;
-       if (IsA(node, RowExpr))
-               return false;
-       if (IsA(node, RowCompareExpr))
-               return false;
-       if (IsA(node, CoalesceExpr))
-               return false;
-       if (IsA(node, MinMaxExpr))
-               return false;
-       if (IsA(node, XmlExpr))
-               return false;
-       if (IsA(node, NullIfExpr))
-               return false;
-
-       return expression_tree_walker(node, expression_returns_set_walker,
-                                                                 context);
-}
-
 /*
  * expression_returns_set_rows
  *       Estimate the number of rows in a set result.
  *
  * We use the product of the rowcount estimates of all the functions in
  * the given tree.     The result is 1 if there are no set-returning functions.
+ *
+ * Note: keep this in sync with expression_returns_set() in nodes/nodeFuncs.c.
  */
 double
 expression_returns_set_rows(Node *clause)
@@ -3936,1156 +3865,3 @@ substitute_actual_srf_parameters_mutator(Node *node,
                                                                   substitute_actual_srf_parameters_mutator,
                                                                   (void *) context);
 }
-
-
-/*
- * Standard expression-tree walking support
- *
- * We used to have near-duplicate code in many different routines that
- * understood how to recurse through an expression node tree.  That was
- * a pain to maintain, and we frequently had bugs due to some particular
- * routine neglecting to support a particular node type.  In most cases,
- * these routines only actually care about certain node types, and don't
- * care about other types except insofar as they have to recurse through
- * non-primitive node types.  Therefore, we now provide generic tree-walking
- * logic to consolidate the redundant "boilerplate" code.  There are
- * two versions: expression_tree_walker() and expression_tree_mutator().
- */
-
-/*--------------------
- * expression_tree_walker() is designed to support routines that traverse
- * a tree in a read-only fashion (although it will also work for routines
- * that modify nodes in-place but never add/delete/replace nodes).
- * A walker routine should look like this:
- *
- * bool my_walker (Node *node, my_struct *context)
- * {
- *             if (node == NULL)
- *                     return false;
- *             // check for nodes that special work is required for, eg:
- *             if (IsA(node, Var))
- *             {
- *                     ... do special actions for Var nodes
- *             }
- *             else if (IsA(node, ...))
- *             {
- *                     ... do special actions for other node types
- *             }
- *             // for any node type not specially processed, do:
- *             return expression_tree_walker(node, my_walker, (void *) context);
- * }
- *
- * The "context" argument points to a struct that holds whatever context
- * information the walker routine needs --- it can be used to return data
- * gathered by the walker, too.  This argument is not touched by
- * expression_tree_walker, but it is passed down to recursive sub-invocations
- * of my_walker.  The tree walk is started from a setup routine that
- * fills in the appropriate context struct, calls my_walker with the top-level
- * node of the tree, and then examines the results.
- *
- * The walker routine should return "false" to continue the tree walk, or
- * "true" to abort the walk and immediately return "true" to the top-level
- * caller.     This can be used to short-circuit the traversal if the walker
- * has found what it came for. "false" is returned to the top-level caller
- * iff no invocation of the walker returned "true".
- *
- * The node types handled by expression_tree_walker include all those
- * normally found in target lists and qualifier clauses during the planning
- * stage.  In particular, it handles List nodes since a cnf-ified qual clause
- * will have List structure at the top level, and it handles TargetEntry nodes
- * so that a scan of a target list can be handled without additional code.
- * Also, RangeTblRef, FromExpr, JoinExpr, and SetOperationStmt nodes are
- * handled, so that query jointrees and setOperation trees can be processed
- * without additional code.
- *
- * expression_tree_walker will handle SubLink nodes by recursing normally
- * into the "testexpr" subtree (which is an expression belonging to the outer
- * plan).  It will also call the walker on the sub-Query node; however, when
- * expression_tree_walker itself is called on a Query node, it does nothing
- * and returns "false".  The net effect is that unless the walker does
- * something special at a Query node, sub-selects will not be visited during
- * an expression tree walk. This is exactly the behavior wanted in many cases
- * --- and for those walkers that do want to recurse into sub-selects, special
- * behavior is typically needed anyway at the entry to a sub-select (such as
- * incrementing a depth counter). A walker that wants to examine sub-selects
- * should include code along the lines of:
- *
- *             if (IsA(node, Query))
- *             {
- *                     adjust context for subquery;
- *                     result = query_tree_walker((Query *) node, my_walker, context,
- *                                                                        0); // adjust flags as needed
- *                     restore context if needed;
- *                     return result;
- *             }
- *
- * query_tree_walker is a convenience routine (see below) that calls the
- * walker on all the expression subtrees of the given Query node.
- *
- * expression_tree_walker will handle SubPlan nodes by recursing normally
- * into the "testexpr" and the "args" list (which are expressions belonging to
- * the outer plan).  It will not touch the completed subplan, however. Since
- * there is no link to the original Query, it is not possible to recurse into
- * subselects of an already-planned expression tree.  This is OK for current
- * uses, but may need to be revisited in future.
- *--------------------
- */
-
-bool
-expression_tree_walker(Node *node,
-                                          bool (*walker) (),
-                                          void *context)
-{
-       ListCell   *temp;
-
-       /*
-        * The walker has already visited the current node, and so we need only
-        * recurse into any sub-nodes it has.
-        *
-        * We assume that the walker is not interested in List nodes per se, so
-        * when we expect a List we just recurse directly to self without
-        * bothering to call the walker.
-        */
-       if (node == NULL)
-               return false;
-
-       /* Guard against stack overflow due to overly complex expressions */
-       check_stack_depth();
-
-       switch (nodeTag(node))
-       {
-               case T_Var:
-               case T_Const:
-               case T_Param:
-               case T_CoerceToDomainValue:
-               case T_CaseTestExpr:
-               case T_SetToDefault:
-               case T_CurrentOfExpr:
-               case T_RangeTblRef:
-                       /* primitive node types with no expression subnodes */
-                       break;
-               case T_Aggref:
-                       {
-                               Aggref     *expr = (Aggref *) node;
-
-                               /* recurse directly on List */
-                               if (expression_tree_walker((Node *) expr->args,
-                                                                                  walker, context))
-                                       return true;
-                       }
-                       break;
-               case T_ArrayRef:
-                       {
-                               ArrayRef   *aref = (ArrayRef *) node;
-
-                               /* recurse directly for upper/lower array index lists */
-                               if (expression_tree_walker((Node *) aref->refupperindexpr,
-                                                                                  walker, context))
-                                       return true;
-                               if (expression_tree_walker((Node *) aref->reflowerindexpr,
-                                                                                  walker, context))
-                                       return true;
-                               /* walker must see the refexpr and refassgnexpr, however */
-                               if (walker(aref->refexpr, context))
-                                       return true;
-                               if (walker(aref->refassgnexpr, context))
-                                       return true;
-                       }
-                       break;
-               case T_FuncExpr:
-                       {
-                               FuncExpr   *expr = (FuncExpr *) node;
-
-                               if (expression_tree_walker((Node *) expr->args,
-                                                                                  walker, context))
-                                       return true;
-                       }
-                       break;
-               case T_OpExpr:
-                       {
-                               OpExpr     *expr = (OpExpr *) node;
-
-                               if (expression_tree_walker((Node *) expr->args,
-                                                                                  walker, context))
-                                       return true;
-                       }
-                       break;
-               case T_DistinctExpr:
-                       {
-                               DistinctExpr *expr = (DistinctExpr *) node;
-
-                               if (expression_tree_walker((Node *) expr->args,
-                                                                                  walker, context))
-                                       return true;
-                       }
-                       break;
-               case T_ScalarArrayOpExpr:
-                       {
-                               ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
-
-                               if (expression_tree_walker((Node *) expr->args,
-                                                                                  walker, context))
-                                       return true;
-                       }
-                       break;
-               case T_BoolExpr:
-                       {
-                               BoolExpr   *expr = (BoolExpr *) node;
-
-                               if (expression_tree_walker((Node *) expr->args,
-                                                                                  walker, context))
-                                       return true;
-                       }
-                       break;
-               case T_SubLink:
-                       {
-                               SubLink    *sublink = (SubLink *) node;
-
-                               if (walker(sublink->testexpr, context))
-                                       return true;
-
-                               /*
-                                * Also invoke the walker on the sublink's Query node, so it
-                                * can recurse into the sub-query if it wants to.
-                                */
-                               return walker(sublink->subselect, context);
-                       }
-                       break;
-               case T_SubPlan:
-                       {
-                               SubPlan    *subplan = (SubPlan *) node;
-
-                               /* recurse into the testexpr, but not into the Plan */
-                               if (walker(subplan->testexpr, context))
-                                       return true;
-                               /* also examine args list */
-                               if (expression_tree_walker((Node *) subplan->args,
-                                                                                  walker, context))
-                                       return true;
-                       }
-                       break;
-               case T_AlternativeSubPlan:
-                       return walker(((AlternativeSubPlan *) node)->subplans, context);
-               case T_FieldSelect:
-                       return walker(((FieldSelect *) node)->arg, context);
-               case T_FieldStore:
-                       {
-                               FieldStore *fstore = (FieldStore *) node;
-
-                               if (walker(fstore->arg, context))
-                                       return true;
-                               if (walker(fstore->newvals, context))
-                                       return true;
-                       }
-                       break;
-               case T_RelabelType:
-                       return walker(((RelabelType *) node)->arg, context);
-               case T_CoerceViaIO:
-                       return walker(((CoerceViaIO *) node)->arg, context);
-               case T_ArrayCoerceExpr:
-                       return walker(((ArrayCoerceExpr *) node)->arg, context);
-               case T_ConvertRowtypeExpr:
-                       return walker(((ConvertRowtypeExpr *) node)->arg, context);
-               case T_CaseExpr:
-                       {
-                               CaseExpr   *caseexpr = (CaseExpr *) node;
-
-                               if (walker(caseexpr->arg, context))
-                                       return true;
-                               /* we assume walker doesn't care about CaseWhens, either */
-                               foreach(temp, caseexpr->args)
-                               {
-                                       CaseWhen   *when = (CaseWhen *) lfirst(temp);
-
-                                       Assert(IsA(when, CaseWhen));
-                                       if (walker(when->expr, context))
-                                               return true;
-                                       if (walker(when->result, context))
-                                               return true;
-                               }
-                               if (walker(caseexpr->defresult, context))
-                                       return true;
-                       }
-                       break;
-               case T_ArrayExpr:
-                       return walker(((ArrayExpr *) node)->elements, context);
-               case T_RowExpr:
-                       return walker(((RowExpr *) node)->args, context);
-               case T_RowCompareExpr:
-                       {
-                               RowCompareExpr *rcexpr = (RowCompareExpr *) node;
-
-                               if (walker(rcexpr->largs, context))
-                                       return true;
-                               if (walker(rcexpr->rargs, context))
-                                       return true;
-                       }
-                       break;
-               case T_CoalesceExpr:
-                       return walker(((CoalesceExpr *) node)->args, context);
-               case T_MinMaxExpr:
-                       return walker(((MinMaxExpr *) node)->args, context);
-               case T_XmlExpr:
-                       {
-                               XmlExpr    *xexpr = (XmlExpr *) node;
-
-                               if (walker(xexpr->named_args, context))
-                                       return true;
-                               /* we assume walker doesn't care about arg_names */
-                               if (walker(xexpr->args, context))
-                                       return true;
-                       }
-                       break;
-               case T_NullIfExpr:
-                       return walker(((NullIfExpr *) node)->args, context);
-               case T_NullTest:
-                       return walker(((NullTest *) node)->arg, context);
-               case T_BooleanTest:
-                       return walker(((BooleanTest *) node)->arg, context);
-               case T_CoerceToDomain:
-                       return walker(((CoerceToDomain *) node)->arg, context);
-               case T_TargetEntry:
-                       return walker(((TargetEntry *) node)->expr, context);
-               case T_Query:
-                       /* Do nothing with a sub-Query, per discussion above */
-                       break;
-               case T_List:
-                       foreach(temp, (List *) node)
-                       {
-                               if (walker((Node *) lfirst(temp), context))
-                                       return true;
-                       }
-                       break;
-               case T_FromExpr:
-                       {
-                               FromExpr   *from = (FromExpr *) node;
-
-                               if (walker(from->fromlist, context))
-                                       return true;
-                               if (walker(from->quals, context))
-                                       return true;
-                       }
-                       break;
-               case T_JoinExpr:
-                       {
-                               JoinExpr   *join = (JoinExpr *) node;
-
-                               if (walker(join->larg, context))
-                                       return true;
-                               if (walker(join->rarg, context))
-                                       return true;
-                               if (walker(join->quals, context))
-                                       return true;
-
-                               /*
-                                * alias clause, using list are deemed uninteresting.
-                                */
-                       }
-                       break;
-               case T_SetOperationStmt:
-                       {
-                               SetOperationStmt *setop = (SetOperationStmt *) node;
-
-                               if (walker(setop->larg, context))
-                                       return true;
-                               if (walker(setop->rarg, context))
-                                       return true;
-
-                               /* groupClauses are deemed uninteresting */
-                       }
-                       break;
-               case T_FlattenedSubLink:
-                       {
-                               FlattenedSubLink *fslink = (FlattenedSubLink *) node;
-
-                               if (expression_tree_walker((Node *) fslink->quals,
-                                                                                  walker, context))
-                                       return true;
-                       }
-                       break;
-               case T_AppendRelInfo:
-                       {
-                               AppendRelInfo *appinfo = (AppendRelInfo *) node;
-
-                               if (expression_tree_walker((Node *) appinfo->translated_vars,
-                                                                                  walker, context))
-                                       return true;
-                       }
-                       break;
-               default:
-                       elog(ERROR, "unrecognized node type: %d",
-                                (int) nodeTag(node));
-                       break;
-       }
-       return false;
-}
-
-/*
- * query_tree_walker --- initiate a walk of a Query's expressions
- *
- * This routine exists just to reduce the number of places that need to know
- * where all the expression subtrees of a Query are.  Note it can be used
- * for starting a walk at top level of a Query regardless of whether the
- * walker intends to descend into subqueries.  It is also useful for
- * descending into subqueries within a walker.
- *
- * Some callers want to suppress visitation of certain items in the sub-Query,
- * typically because they need to process them specially, or don't actually
- * want to recurse into subqueries.  This is supported by the flags argument,
- * which is the bitwise OR of flag values to suppress visitation of
- * indicated items.  (More flag bits may be added as needed.)
- */
-bool
-query_tree_walker(Query *query,
-                                 bool (*walker) (),
-                                 void *context,
-                                 int flags)
-{
-       Assert(query != NULL && IsA(query, Query));
-
-       if (walker((Node *) query->targetList, context))
-               return true;
-       if (walker((Node *) query->returningList, context))
-               return true;
-       if (walker((Node *) query->jointree, context))
-               return true;
-       if (walker(query->setOperations, context))
-               return true;
-       if (walker(query->havingQual, context))
-               return true;
-       if (walker(query->limitOffset, context))
-               return true;
-       if (walker(query->limitCount, context))
-               return true;
-       if (range_table_walker(query->rtable, walker, context, flags))
-               return true;
-       return false;
-}
-
-/*
- * range_table_walker is just the part of query_tree_walker that scans
- * a query's rangetable.  This is split out since it can be useful on
- * its own.
- */
-bool
-range_table_walker(List *rtable,
-                                  bool (*walker) (),
-                                  void *context,
-                                  int flags)
-{
-       ListCell   *rt;
-
-       foreach(rt, rtable)
-       {
-               RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
-
-               switch (rte->rtekind)
-               {
-                       case RTE_RELATION:
-                       case RTE_SPECIAL:
-                               /* nothing to do */
-                               break;
-                       case RTE_SUBQUERY:
-                               if (!(flags & QTW_IGNORE_RT_SUBQUERIES))
-                                       if (walker(rte->subquery, context))
-                                               return true;
-                               break;
-                       case RTE_JOIN:
-                               if (!(flags & QTW_IGNORE_JOINALIASES))
-                                       if (walker(rte->joinaliasvars, context))
-                                               return true;
-                               break;
-                       case RTE_FUNCTION:
-                               if (walker(rte->funcexpr, context))
-                                       return true;
-                               break;
-                       case RTE_VALUES:
-                               if (walker(rte->values_lists, context))
-                                       return true;
-                               break;
-               }
-       }
-       return false;
-}
-
-
-/*--------------------
- * expression_tree_mutator() is designed to support routines that make a
- * modified copy of an expression tree, with some nodes being added,
- * removed, or replaced by new subtrees.  The original tree is (normally)
- * not changed.  Each recursion level is responsible for returning a copy of
- * (or appropriately modified substitute for) the subtree it is handed.
- * A mutator routine should look like this:
- *
- * Node * my_mutator (Node *node, my_struct *context)
- * {
- *             if (node == NULL)
- *                     return NULL;
- *             // check for nodes that special work is required for, eg:
- *             if (IsA(node, Var))
- *             {
- *                     ... create and return modified copy of Var node
- *             }
- *             else if (IsA(node, ...))
- *             {
- *                     ... do special transformations of other node types
- *             }
- *             // for any node type not specially processed, do:
- *             return expression_tree_mutator(node, my_mutator, (void *) context);
- * }
- *
- * The "context" argument points to a struct that holds whatever context
- * information the mutator routine needs --- it can be used to return extra
- * data gathered by the mutator, too.  This argument is not touched by
- * expression_tree_mutator, but it is passed down to recursive sub-invocations
- * of my_mutator.  The tree walk is started from a setup routine that
- * fills in the appropriate context struct, calls my_mutator with the
- * top-level node of the tree, and does any required post-processing.
- *
- * Each level of recursion must return an appropriately modified Node.
- * If expression_tree_mutator() is called, it will make an exact copy
- * of the given Node, but invoke my_mutator() to copy the sub-node(s)
- * of that Node.  In this way, my_mutator() has full control over the
- * copying process but need not directly deal with expression trees
- * that it has no interest in.
- *
- * Just as for expression_tree_walker, the node types handled by
- * expression_tree_mutator include all those normally found in target lists
- * and qualifier clauses during the planning stage.
- *
- * expression_tree_mutator will handle SubLink nodes by recursing normally
- * into the "testexpr" subtree (which is an expression belonging to the outer
- * plan).  It will also call the mutator on the sub-Query node; however, when
- * expression_tree_mutator itself is called on a Query node, it does nothing
- * and returns the unmodified Query node.  The net effect is that unless the
- * mutator does something special at a Query node, sub-selects will not be
- * visited or modified; the original sub-select will be linked to by the new
- * SubLink node.  Mutators that want to descend into sub-selects will usually
- * do so by recognizing Query nodes and calling query_tree_mutator (below).
- *
- * expression_tree_mutator will handle a SubPlan node by recursing into the
- * "testexpr" and the "args" list (which belong to the outer plan), but it
- * will simply copy the link to the inner plan, since that's typically what
- * expression tree mutators want.  A mutator that wants to modify the subplan
- * can force appropriate behavior by recognizing SubPlan expression nodes
- * and doing the right thing.
- *--------------------
- */
-
-Node *
-expression_tree_mutator(Node *node,
-                                               Node *(*mutator) (),
-                                               void *context)
-{
-       /*
-        * The mutator has already decided not to modify the current node, but we
-        * must call the mutator for any sub-nodes.
-        */
-
-#define FLATCOPY(newnode, node, nodetype)  \
-       ( (newnode) = (nodetype *) palloc(sizeof(nodetype)), \
-         memcpy((newnode), (node), sizeof(nodetype)) )
-
-#define CHECKFLATCOPY(newnode, node, nodetype) \
-       ( AssertMacro(IsA((node), nodetype)), \
-         (newnode) = (nodetype *) palloc(sizeof(nodetype)), \
-         memcpy((newnode), (node), sizeof(nodetype)) )
-
-#define MUTATE(newfield, oldfield, fieldtype)  \
-               ( (newfield) = (fieldtype) mutator((Node *) (oldfield), context) )
-
-       if (node == NULL)
-               return NULL;
-
-       /* Guard against stack overflow due to overly complex expressions */
-       check_stack_depth();
-
-       switch (nodeTag(node))
-       {
-                       /*
-                        * Primitive node types with no expression subnodes.  Var and
-                        * Const are frequent enough to deserve special cases, the others
-                        * we just use copyObject for.
-                        */
-               case T_Var:
-                       {
-                               Var                *var = (Var *) node;
-                               Var                *newnode;
-
-                               FLATCOPY(newnode, var, Var);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_Const:
-                       {
-                               Const      *oldnode = (Const *) node;
-                               Const      *newnode;
-
-                               FLATCOPY(newnode, oldnode, Const);
-                               /* XXX we don't bother with datumCopy; should we? */
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_Param:
-               case T_CoerceToDomainValue:
-               case T_CaseTestExpr:
-               case T_SetToDefault:
-               case T_CurrentOfExpr:
-               case T_RangeTblRef:
-                       return (Node *) copyObject(node);
-               case T_Aggref:
-                       {
-                               Aggref     *aggref = (Aggref *) node;
-                               Aggref     *newnode;
-
-                               FLATCOPY(newnode, aggref, Aggref);
-                               MUTATE(newnode->args, aggref->args, List *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_ArrayRef:
-                       {
-                               ArrayRef   *arrayref = (ArrayRef *) node;
-                               ArrayRef   *newnode;
-
-                               FLATCOPY(newnode, arrayref, ArrayRef);
-                               MUTATE(newnode->refupperindexpr, arrayref->refupperindexpr,
-                                          List *);
-                               MUTATE(newnode->reflowerindexpr, arrayref->reflowerindexpr,
-                                          List *);
-                               MUTATE(newnode->refexpr, arrayref->refexpr,
-                                          Expr *);
-                               MUTATE(newnode->refassgnexpr, arrayref->refassgnexpr,
-                                          Expr *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_FuncExpr:
-                       {
-                               FuncExpr   *expr = (FuncExpr *) node;
-                               FuncExpr   *newnode;
-
-                               FLATCOPY(newnode, expr, FuncExpr);
-                               MUTATE(newnode->args, expr->args, List *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_OpExpr:
-                       {
-                               OpExpr     *expr = (OpExpr *) node;
-                               OpExpr     *newnode;
-
-                               FLATCOPY(newnode, expr, OpExpr);
-                               MUTATE(newnode->args, expr->args, List *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_DistinctExpr:
-                       {
-                               DistinctExpr *expr = (DistinctExpr *) node;
-                               DistinctExpr *newnode;
-
-                               FLATCOPY(newnode, expr, DistinctExpr);
-                               MUTATE(newnode->args, expr->args, List *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_ScalarArrayOpExpr:
-                       {
-                               ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
-                               ScalarArrayOpExpr *newnode;
-
-                               FLATCOPY(newnode, expr, ScalarArrayOpExpr);
-                               MUTATE(newnode->args, expr->args, List *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_BoolExpr:
-                       {
-                               BoolExpr   *expr = (BoolExpr *) node;
-                               BoolExpr   *newnode;
-
-                               FLATCOPY(newnode, expr, BoolExpr);
-                               MUTATE(newnode->args, expr->args, List *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_SubLink:
-                       {
-                               SubLink    *sublink = (SubLink *) node;
-                               SubLink    *newnode;
-
-                               FLATCOPY(newnode, sublink, SubLink);
-                               MUTATE(newnode->testexpr, sublink->testexpr, Node *);
-
-                               /*
-                                * Also invoke the mutator on the sublink's Query node, so it
-                                * can recurse into the sub-query if it wants to.
-                                */
-                               MUTATE(newnode->subselect, sublink->subselect, Node *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_SubPlan:
-                       {
-                               SubPlan    *subplan = (SubPlan *) node;
-                               SubPlan    *newnode;
-
-                               FLATCOPY(newnode, subplan, SubPlan);
-                               /* transform testexpr */
-                               MUTATE(newnode->testexpr, subplan->testexpr, Node *);
-                               /* transform args list (params to be passed to subplan) */
-                               MUTATE(newnode->args, subplan->args, List *);
-                               /* but not the sub-Plan itself, which is referenced as-is */
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_AlternativeSubPlan:
-                       {
-                               AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
-                               AlternativeSubPlan *newnode;
-
-                               FLATCOPY(newnode, asplan, AlternativeSubPlan);
-                               MUTATE(newnode->subplans, asplan->subplans, List *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_FieldSelect:
-                       {
-                               FieldSelect *fselect = (FieldSelect *) node;
-                               FieldSelect *newnode;
-
-                               FLATCOPY(newnode, fselect, FieldSelect);
-                               MUTATE(newnode->arg, fselect->arg, Expr *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_FieldStore:
-                       {
-                               FieldStore *fstore = (FieldStore *) node;
-                               FieldStore *newnode;
-
-                               FLATCOPY(newnode, fstore, FieldStore);
-                               MUTATE(newnode->arg, fstore->arg, Expr *);
-                               MUTATE(newnode->newvals, fstore->newvals, List *);
-                               newnode->fieldnums = list_copy(fstore->fieldnums);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_RelabelType:
-                       {
-                               RelabelType *relabel = (RelabelType *) node;
-                               RelabelType *newnode;
-
-                               FLATCOPY(newnode, relabel, RelabelType);
-                               MUTATE(newnode->arg, relabel->arg, Expr *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_CoerceViaIO:
-                       {
-                               CoerceViaIO *iocoerce = (CoerceViaIO *) node;
-                               CoerceViaIO *newnode;
-
-                               FLATCOPY(newnode, iocoerce, CoerceViaIO);
-                               MUTATE(newnode->arg, iocoerce->arg, Expr *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_ArrayCoerceExpr:
-                       {
-                               ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
-                               ArrayCoerceExpr *newnode;
-
-                               FLATCOPY(newnode, acoerce, ArrayCoerceExpr);
-                               MUTATE(newnode->arg, acoerce->arg, Expr *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_ConvertRowtypeExpr:
-                       {
-                               ConvertRowtypeExpr *convexpr = (ConvertRowtypeExpr *) node;
-                               ConvertRowtypeExpr *newnode;
-
-                               FLATCOPY(newnode, convexpr, ConvertRowtypeExpr);
-                               MUTATE(newnode->arg, convexpr->arg, Expr *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_CaseExpr:
-                       {
-                               CaseExpr   *caseexpr = (CaseExpr *) node;
-                               CaseExpr   *newnode;
-
-                               FLATCOPY(newnode, caseexpr, CaseExpr);
-                               MUTATE(newnode->arg, caseexpr->arg, Expr *);
-                               MUTATE(newnode->args, caseexpr->args, List *);
-                               MUTATE(newnode->defresult, caseexpr->defresult, Expr *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_CaseWhen:
-                       {
-                               CaseWhen   *casewhen = (CaseWhen *) node;
-                               CaseWhen   *newnode;
-
-                               FLATCOPY(newnode, casewhen, CaseWhen);
-                               MUTATE(newnode->expr, casewhen->expr, Expr *);
-                               MUTATE(newnode->result, casewhen->result, Expr *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_ArrayExpr:
-                       {
-                               ArrayExpr  *arrayexpr = (ArrayExpr *) node;
-                               ArrayExpr  *newnode;
-
-                               FLATCOPY(newnode, arrayexpr, ArrayExpr);
-                               MUTATE(newnode->elements, arrayexpr->elements, List *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_RowExpr:
-                       {
-                               RowExpr    *rowexpr = (RowExpr *) node;
-                               RowExpr    *newnode;
-
-                               FLATCOPY(newnode, rowexpr, RowExpr);
-                               MUTATE(newnode->args, rowexpr->args, List *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_RowCompareExpr:
-                       {
-                               RowCompareExpr *rcexpr = (RowCompareExpr *) node;
-                               RowCompareExpr *newnode;
-
-                               FLATCOPY(newnode, rcexpr, RowCompareExpr);
-                               MUTATE(newnode->largs, rcexpr->largs, List *);
-                               MUTATE(newnode->rargs, rcexpr->rargs, List *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_CoalesceExpr:
-                       {
-                               CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
-                               CoalesceExpr *newnode;
-
-                               FLATCOPY(newnode, coalesceexpr, CoalesceExpr);
-                               MUTATE(newnode->args, coalesceexpr->args, List *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_MinMaxExpr:
-                       {
-                               MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
-                               MinMaxExpr *newnode;
-
-                               FLATCOPY(newnode, minmaxexpr, MinMaxExpr);
-                               MUTATE(newnode->args, minmaxexpr->args, List *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_XmlExpr:
-                       {
-                               XmlExpr    *xexpr = (XmlExpr *) node;
-                               XmlExpr    *newnode;
-
-                               FLATCOPY(newnode, xexpr, XmlExpr);
-                               MUTATE(newnode->named_args, xexpr->named_args, List *);
-                               /* assume mutator does not care about arg_names */
-                               MUTATE(newnode->args, xexpr->args, List *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_NullIfExpr:
-                       {
-                               NullIfExpr *expr = (NullIfExpr *) node;
-                               NullIfExpr *newnode;
-
-                               FLATCOPY(newnode, expr, NullIfExpr);
-                               MUTATE(newnode->args, expr->args, List *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_NullTest:
-                       {
-                               NullTest   *ntest = (NullTest *) node;
-                               NullTest   *newnode;
-
-                               FLATCOPY(newnode, ntest, NullTest);
-                               MUTATE(newnode->arg, ntest->arg, Expr *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_BooleanTest:
-                       {
-                               BooleanTest *btest = (BooleanTest *) node;
-                               BooleanTest *newnode;
-
-                               FLATCOPY(newnode, btest, BooleanTest);
-                               MUTATE(newnode->arg, btest->arg, Expr *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_CoerceToDomain:
-                       {
-                               CoerceToDomain *ctest = (CoerceToDomain *) node;
-                               CoerceToDomain *newnode;
-
-                               FLATCOPY(newnode, ctest, CoerceToDomain);
-                               MUTATE(newnode->arg, ctest->arg, Expr *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_TargetEntry:
-                       {
-                               TargetEntry *targetentry = (TargetEntry *) node;
-                               TargetEntry *newnode;
-
-                               FLATCOPY(newnode, targetentry, TargetEntry);
-                               MUTATE(newnode->expr, targetentry->expr, Expr *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_Query:
-                       /* Do nothing with a sub-Query, per discussion above */
-                       return node;
-               case T_List:
-                       {
-                               /*
-                                * We assume the mutator isn't interested in the list nodes
-                                * per se, so just invoke it on each list element. NOTE: this
-                                * would fail badly on a list with integer elements!
-                                */
-                               List       *resultlist;
-                               ListCell   *temp;
-
-                               resultlist = NIL;
-                               foreach(temp, (List *) node)
-                               {
-                                       resultlist = lappend(resultlist,
-                                                                                mutator((Node *) lfirst(temp),
-                                                                                                context));
-                               }
-                               return (Node *) resultlist;
-                       }
-                       break;
-               case T_FromExpr:
-                       {
-                               FromExpr   *from = (FromExpr *) node;
-                               FromExpr   *newnode;
-
-                               FLATCOPY(newnode, from, FromExpr);
-                               MUTATE(newnode->fromlist, from->fromlist, List *);
-                               MUTATE(newnode->quals, from->quals, Node *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_JoinExpr:
-                       {
-                               JoinExpr   *join = (JoinExpr *) node;
-                               JoinExpr   *newnode;
-
-                               FLATCOPY(newnode, join, JoinExpr);
-                               MUTATE(newnode->larg, join->larg, Node *);
-                               MUTATE(newnode->rarg, join->rarg, Node *);
-                               MUTATE(newnode->quals, join->quals, Node *);
-                               /* We do not mutate alias or using by default */
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_SetOperationStmt:
-                       {
-                               SetOperationStmt *setop = (SetOperationStmt *) node;
-                               SetOperationStmt *newnode;
-
-                               FLATCOPY(newnode, setop, SetOperationStmt);
-                               MUTATE(newnode->larg, setop->larg, Node *);
-                               MUTATE(newnode->rarg, setop->rarg, Node *);
-                               /* We do not mutate groupClauses by default */
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_FlattenedSubLink:
-                       {
-                               FlattenedSubLink *fslink = (FlattenedSubLink *) node;
-                               FlattenedSubLink *newnode;
-
-                               FLATCOPY(newnode, fslink, FlattenedSubLink);
-                               /* Assume we need not copy the relids bitmapsets */
-                               MUTATE(newnode->quals, fslink->quals, Expr *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               case T_AppendRelInfo:
-                       {
-                               AppendRelInfo *appinfo = (AppendRelInfo *) node;
-                               AppendRelInfo *newnode;
-
-                               FLATCOPY(newnode, appinfo, AppendRelInfo);
-                               MUTATE(newnode->translated_vars, appinfo->translated_vars, List *);
-                               return (Node *) newnode;
-                       }
-                       break;
-               default:
-                       elog(ERROR, "unrecognized node type: %d",
-                                (int) nodeTag(node));
-                       break;
-       }
-       /* can't get here, but keep compiler happy */
-       return NULL;
-}
-
-
-/*
- * query_tree_mutator --- initiate modification of a Query's expressions
- *
- * This routine exists just to reduce the number of places that need to know
- * where all the expression subtrees of a Query are.  Note it can be used
- * for starting a walk at top level of a Query regardless of whether the
- * mutator intends to descend into subqueries. It is also useful for
- * descending into subqueries within a mutator.
- *
- * Some callers want to suppress mutating of certain items in the Query,
- * typically because they need to process them specially, or don't actually
- * want to recurse into subqueries.  This is supported by the flags argument,
- * which is the bitwise OR of flag values to suppress mutating of
- * indicated items.  (More flag bits may be added as needed.)
- *
- * Normally the Query node itself is copied, but some callers want it to be
- * modified in-place; they must pass QTW_DONT_COPY_QUERY in flags.     All
- * modified substructure is safely copied in any case.
- */
-Query *
-query_tree_mutator(Query *query,
-                                  Node *(*mutator) (),
-                                  void *context,
-                                  int flags)
-{
-       Assert(query != NULL && IsA(query, Query));
-
-       if (!(flags & QTW_DONT_COPY_QUERY))
-       {
-               Query      *newquery;
-
-               FLATCOPY(newquery, query, Query);
-               query = newquery;
-       }
-
-       MUTATE(query->targetList, query->targetList, List *);
-       MUTATE(query->returningList, query->returningList, List *);
-       MUTATE(query->jointree, query->jointree, FromExpr *);
-       MUTATE(query->setOperations, query->setOperations, Node *);
-       MUTATE(query->havingQual, query->havingQual, Node *);
-       MUTATE(query->limitOffset, query->limitOffset, Node *);
-       MUTATE(query->limitCount, query->limitCount, Node *);
-       query->rtable = range_table_mutator(query->rtable,
-                                                                               mutator, context, flags);
-       return query;
-}
-
-/*
- * range_table_mutator is just the part of query_tree_mutator that processes
- * a query's rangetable.  This is split out since it can be useful on
- * its own.
- */
-List *
-range_table_mutator(List *rtable,
-                                       Node *(*mutator) (),
-                                       void *context,
-                                       int flags)
-{
-       List       *newrt = NIL;
-       ListCell   *rt;
-
-       foreach(rt, rtable)
-       {
-               RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
-               RangeTblEntry *newrte;
-
-               FLATCOPY(newrte, rte, RangeTblEntry);
-               switch (rte->rtekind)
-               {
-                       case RTE_RELATION:
-                       case RTE_SPECIAL:
-                               /* we don't bother to copy eref, aliases, etc; OK? */
-                               break;
-                       case RTE_SUBQUERY:
-                               if (!(flags & QTW_IGNORE_RT_SUBQUERIES))
-                               {
-                                       CHECKFLATCOPY(newrte->subquery, rte->subquery, Query);
-                                       MUTATE(newrte->subquery, newrte->subquery, Query *);
-                               }
-                               else
-                               {
-                                       /* else, copy RT subqueries as-is */
-                                       newrte->subquery = copyObject(rte->subquery);
-                               }
-                               break;
-                       case RTE_JOIN:
-                               if (!(flags & QTW_IGNORE_JOINALIASES))
-                                       MUTATE(newrte->joinaliasvars, rte->joinaliasvars, List *);
-                               else
-                               {
-                                       /* else, copy join aliases as-is */
-                                       newrte->joinaliasvars = copyObject(rte->joinaliasvars);
-                               }
-                               break;
-                       case RTE_FUNCTION:
-                               MUTATE(newrte->funcexpr, rte->funcexpr, Node *);
-                               break;
-                       case RTE_VALUES:
-                               MUTATE(newrte->values_lists, rte->values_lists, List *);
-                               break;
-               }
-               newrt = lappend(newrt, newrte);
-       }
-       return newrt;
-}
-
-/*
- * query_or_expression_tree_walker --- hybrid form
- *
- * This routine will invoke query_tree_walker if called on a Query node,
- * else will invoke the walker directly.  This is a useful way of starting
- * the recursion when the walker's normal change of state is not appropriate
- * for the outermost Query node.
- */
-bool
-query_or_expression_tree_walker(Node *node,
-                                                               bool (*walker) (),
-                                                               void *context,
-                                                               int flags)
-{
-       if (node && IsA(node, Query))
-               return query_tree_walker((Query *) node,
-                                                                walker,
-                                                                context,
-                                                                flags);
-       else
-               return walker(node, context);
-}
-
-/*
- * query_or_expression_tree_mutator --- hybrid form
- *
- * This routine will invoke query_tree_mutator if called on a Query node,
- * else will invoke the mutator directly.  This is a useful way of starting
- * the recursion when the mutator's normal change of state is not appropriate
- * for the outermost Query node.
- */
-Node *
-query_or_expression_tree_mutator(Node *node,
-                                                                Node *(*mutator) (),
-                                                                void *context,
-                                                                int flags)
-{
-       if (node && IsA(node, Query))
-               return (Node *) query_tree_mutator((Query *) node,
-                                                                                  mutator,
-                                                                                  context,
-                                                                                  flags);
-       else
-               return mutator(node, context);
-}
index 30e841b487d3b6ff2b9671ed59106b54477aaccc..8f025ac3a425e6254cae5c8d09fd948481c72f40 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.149 2008/08/16 00:01:36 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.150 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "catalog/pg_inherits.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/plancat.h"
 #include "optimizer/predtest.h"
 #include "optimizer/prep.h"
-#include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteManip.h"
index 4a1a6056e3bb5b1b5c74e313ef8ea0912194836f..6d9934b578e52f2d547af181b872a65ee6cf12ce 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.19 2008/01/12 00:11:39 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.20 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,9 +19,9 @@
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 #include "executor/executor.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/predtest.h"
-#include "parser/parse_expr.h"
 #include "utils/array.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
index b2fb112ebefff49a5a42ff7527078ef859896eb0..2fd16afb5f965d62fcb3cb41743125355f933dfd 100644 (file)
@@ -8,16 +8,16 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/tlist.c,v 1.81 2008/08/07 19:35:02 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/tlist.c,v 1.82 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/tlist.h"
 #include "optimizer/var.h"
-#include "parser/parse_expr.h"
 #include "utils/lsyscache.h"
 
 
index f9bd59c799bce873b4f2c26cfafa34ef36a2d256..85f34e494278420765bcb665682583f7b331798b 100644 (file)
@@ -8,14 +8,14 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.76 2008/08/22 00:16:04 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.77 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/sysattr.h"
-#include "optimizer/clauses.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/prep.h"
 #include "optimizer/var.h"
 #include "parser/parsetree.h"
index 3de232ba71bd18cc587641ed2bffd84eb7bea685..2086c3321f03a6a2ae5e21eef76e4f8fe23a2fd1 100644 (file)
@@ -17,7 +17,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.376 2008/08/07 01:11:51 tgl Exp $
+ *     $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.377 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "catalog/pg_type.h"
 #include "nodes/makefuncs.h"
-#include "optimizer/clauses.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/var.h"
 #include "parser/analyze.h"
 #include "parser/parse_agg.h"
 #include "parser/parse_clause.h"
 #include "parser/parse_coerce.h"
-#include "parser/parse_expr.h"
 #include "parser/parse_oper.h"
 #include "parser/parse_relation.h"
 #include "parser/parse_target.h"
index b5fbd0f78d54cb608d0581135368b9389ea3ae04..b635c3260c9bdc876dea713cd3dbb691cb3d730a 100644 (file)
@@ -8,14 +8,14 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.80 2008/08/02 21:32:00 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.81 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "nodes/makefuncs.h"
-#include "optimizer/clauses.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/tlist.h"
 #include "optimizer/var.h"
 #include "parser/parse_agg.h"
index 79b45414d47fe94e3a1454b689c4adf87559a6a6..aa0b9fd09e40c2820131959b04f41b07d7871967 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.175 2008/08/07 01:11:51 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.176 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,7 +20,7 @@
 #include "catalog/pg_type.h"
 #include "commands/defrem.h"
 #include "nodes/makefuncs.h"
-#include "optimizer/clauses.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/tlist.h"
 #include "optimizer/var.h"
 #include "parser/analyze.h"
index df1fb8526de55b46e33507b9d66b9e58fb96ffeb..1244498ffb291b67d35917a6fdddb54b0d8d759d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.163 2008/07/30 21:23:17 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.164 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,9 +18,8 @@
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 #include "nodes/makefuncs.h"
-#include "optimizer/clauses.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/parse_coerce.h"
-#include "parser/parse_expr.h"
 #include "parser/parse_func.h"
 #include "parser/parse_relation.h"
 #include "parser/parse_type.h"
index 6309525cabf97d0172d1e7be4326ca55dbc5d60f..4257b91a8e92b285d22aba140a3d7463852e427e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.230 2008/08/22 00:16:04 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.231 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "catalog/pg_type.h"
 #include "commands/dbcommands.h"
-#include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
-#include "nodes/plannodes.h"
-#include "optimizer/clauses.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/analyze.h"
-#include "parser/gramparse.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_func.h"
@@ -1863,484 +1860,6 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
        return result;
 }
 
-/*
- *     exprType -
- *       returns the Oid of the type of the expression. (Used for typechecking.)
- */
-Oid
-exprType(Node *expr)
-{
-       Oid                     type;
-
-       if (!expr)
-               return InvalidOid;
-
-       switch (nodeTag(expr))
-       {
-               case T_Var:
-                       type = ((Var *) expr)->vartype;
-                       break;
-               case T_Const:
-                       type = ((Const *) expr)->consttype;
-                       break;
-               case T_Param:
-                       type = ((Param *) expr)->paramtype;
-                       break;
-               case T_Aggref:
-                       type = ((Aggref *) expr)->aggtype;
-                       break;
-               case T_ArrayRef:
-                       {
-                               ArrayRef   *arrayref = (ArrayRef *) expr;
-
-                               /* slice and/or store operations yield the array type */
-                               if (arrayref->reflowerindexpr || arrayref->refassgnexpr)
-                                       type = arrayref->refarraytype;
-                               else
-                                       type = arrayref->refelemtype;
-                       }
-                       break;
-               case T_FuncExpr:
-                       type = ((FuncExpr *) expr)->funcresulttype;
-                       break;
-               case T_OpExpr:
-                       type = ((OpExpr *) expr)->opresulttype;
-                       break;
-               case T_DistinctExpr:
-                       type = ((DistinctExpr *) expr)->opresulttype;
-                       break;
-               case T_ScalarArrayOpExpr:
-                       type = BOOLOID;
-                       break;
-               case T_BoolExpr:
-                       type = BOOLOID;
-                       break;
-               case T_SubLink:
-                       {
-                               SubLink    *sublink = (SubLink *) expr;
-
-                               if (sublink->subLinkType == EXPR_SUBLINK ||
-                                       sublink->subLinkType == ARRAY_SUBLINK)
-                               {
-                                       /* get the type of the subselect's first target column */
-                                       Query      *qtree = (Query *) sublink->subselect;
-                                       TargetEntry *tent;
-
-                                       if (!qtree || !IsA(qtree, Query))
-                                               elog(ERROR, "cannot get type for untransformed sublink");
-                                       tent = (TargetEntry *) linitial(qtree->targetList);
-                                       Assert(IsA(tent, TargetEntry));
-                                       Assert(!tent->resjunk);
-                                       type = exprType((Node *) tent->expr);
-                                       if (sublink->subLinkType == ARRAY_SUBLINK)
-                                       {
-                                               type = get_array_type(type);
-                                               if (!OidIsValid(type))
-                                                       ereport(ERROR,
-                                                                       (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                                                        errmsg("could not find array type for data type %s",
-                                                       format_type_be(exprType((Node *) tent->expr)))));
-                                       }
-                               }
-                               else
-                               {
-                                       /* for all other sublink types, result is boolean */
-                                       type = BOOLOID;
-                               }
-                       }
-                       break;
-               case T_SubPlan:
-                       {
-                               /*
-                                * Although the parser does not ever deal with already-planned
-                                * expression trees, we support SubPlan nodes in this routine
-                                * for the convenience of ruleutils.c.
-                                */
-                               SubPlan    *subplan = (SubPlan *) expr;
-
-                               if (subplan->subLinkType == EXPR_SUBLINK ||
-                                       subplan->subLinkType == ARRAY_SUBLINK)
-                               {
-                                       /* get the type of the subselect's first target column */
-                                       type = subplan->firstColType;
-                                       if (subplan->subLinkType == ARRAY_SUBLINK)
-                                       {
-                                               type = get_array_type(type);
-                                               if (!OidIsValid(type))
-                                                       ereport(ERROR,
-                                                                       (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                                                        errmsg("could not find array type for data type %s",
-                                                                       format_type_be(subplan->firstColType))));
-                                       }
-                               }
-                               else
-                               {
-                                       /* for all other subplan types, result is boolean */
-                                       type = BOOLOID;
-                               }
-                       }
-                       break;
-               case T_AlternativeSubPlan:
-                       {
-                               /* As above, supported for the convenience of ruleutils.c */
-                               AlternativeSubPlan *asplan = (AlternativeSubPlan *) expr;
-
-                               /* subplans should all return the same thing */
-                               type = exprType((Node *) linitial(asplan->subplans));
-                       }
-                       break;
-               case T_FieldSelect:
-                       type = ((FieldSelect *) expr)->resulttype;
-                       break;
-               case T_FieldStore:
-                       type = ((FieldStore *) expr)->resulttype;
-                       break;
-               case T_RelabelType:
-                       type = ((RelabelType *) expr)->resulttype;
-                       break;
-               case T_CoerceViaIO:
-                       type = ((CoerceViaIO *) expr)->resulttype;
-                       break;
-               case T_ArrayCoerceExpr:
-                       type = ((ArrayCoerceExpr *) expr)->resulttype;
-                       break;
-               case T_ConvertRowtypeExpr:
-                       type = ((ConvertRowtypeExpr *) expr)->resulttype;
-                       break;
-               case T_CaseExpr:
-                       type = ((CaseExpr *) expr)->casetype;
-                       break;
-               case T_CaseTestExpr:
-                       type = ((CaseTestExpr *) expr)->typeId;
-                       break;
-               case T_ArrayExpr:
-                       type = ((ArrayExpr *) expr)->array_typeid;
-                       break;
-               case T_RowExpr:
-                       type = ((RowExpr *) expr)->row_typeid;
-                       break;
-               case T_RowCompareExpr:
-                       type = BOOLOID;
-                       break;
-               case T_CoalesceExpr:
-                       type = ((CoalesceExpr *) expr)->coalescetype;
-                       break;
-               case T_MinMaxExpr:
-                       type = ((MinMaxExpr *) expr)->minmaxtype;
-                       break;
-               case T_XmlExpr:
-                       if (((XmlExpr *) expr)->op == IS_DOCUMENT)
-                               type = BOOLOID;
-                       else if (((XmlExpr *) expr)->op == IS_XMLSERIALIZE)
-                               type = TEXTOID;
-                       else
-                               type = XMLOID;
-                       break;
-               case T_NullIfExpr:
-                       type = exprType((Node *) linitial(((NullIfExpr *) expr)->args));
-                       break;
-               case T_NullTest:
-                       type = BOOLOID;
-                       break;
-               case T_BooleanTest:
-                       type = BOOLOID;
-                       break;
-               case T_CoerceToDomain:
-                       type = ((CoerceToDomain *) expr)->resulttype;
-                       break;
-               case T_CoerceToDomainValue:
-                       type = ((CoerceToDomainValue *) expr)->typeId;
-                       break;
-               case T_SetToDefault:
-                       type = ((SetToDefault *) expr)->typeId;
-                       break;
-               case T_CurrentOfExpr:
-                       type = BOOLOID;
-                       break;
-               default:
-                       elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
-                       type = InvalidOid;      /* keep compiler quiet */
-                       break;
-       }
-       return type;
-}
-
-/*
- *     exprTypmod -
- *       returns the type-specific attrmod of the expression, if it can be
- *       determined.  In most cases, it can't and we return -1.
- */
-int32
-exprTypmod(Node *expr)
-{
-       if (!expr)
-               return -1;
-
-       switch (nodeTag(expr))
-       {
-               case T_Var:
-                       return ((Var *) expr)->vartypmod;
-               case T_Const:
-                       return ((Const *) expr)->consttypmod;
-               case T_Param:
-                       return ((Param *) expr)->paramtypmod;
-               case T_ArrayRef:
-                       /* typmod is the same for array or element */
-                       return ((ArrayRef *) expr)->reftypmod;
-               case T_FuncExpr:
-                       {
-                               int32           coercedTypmod;
-
-                               /* Be smart about length-coercion functions... */
-                               if (exprIsLengthCoercion(expr, &coercedTypmod))
-                                       return coercedTypmod;
-                       }
-                       break;
-               case T_SubLink:
-                       {
-                               SubLink    *sublink = (SubLink *) expr;
-
-                               if (sublink->subLinkType == EXPR_SUBLINK ||
-                                       sublink->subLinkType == ARRAY_SUBLINK)
-                               {
-                                       /* get the typmod of the subselect's first target column */
-                                       Query      *qtree = (Query *) sublink->subselect;
-                                       TargetEntry *tent;
-
-                                       if (!qtree || !IsA(qtree, Query))
-                                               elog(ERROR, "cannot get type for untransformed sublink");
-                                       tent = (TargetEntry *) linitial(qtree->targetList);
-                                       Assert(IsA(tent, TargetEntry));
-                                       Assert(!tent->resjunk);
-                                       return exprTypmod((Node *) tent->expr);
-                                       /* note we don't need to care if it's an array */
-                               }
-                       }
-                       break;
-               case T_FieldSelect:
-                       return ((FieldSelect *) expr)->resulttypmod;
-               case T_RelabelType:
-                       return ((RelabelType *) expr)->resulttypmod;
-               case T_ArrayCoerceExpr:
-                       return ((ArrayCoerceExpr *) expr)->resulttypmod;
-               case T_CaseExpr:
-                       {
-                               /*
-                                * If all the alternatives agree on type/typmod, return that
-                                * typmod, else use -1
-                                */
-                               CaseExpr   *cexpr = (CaseExpr *) expr;
-                               Oid                     casetype = cexpr->casetype;
-                               int32           typmod;
-                               ListCell   *arg;
-
-                               if (!cexpr->defresult)
-                                       return -1;
-                               if (exprType((Node *) cexpr->defresult) != casetype)
-                                       return -1;
-                               typmod = exprTypmod((Node *) cexpr->defresult);
-                               if (typmod < 0)
-                                       return -1;      /* no point in trying harder */
-                               foreach(arg, cexpr->args)
-                               {
-                                       CaseWhen   *w = (CaseWhen *) lfirst(arg);
-
-                                       Assert(IsA(w, CaseWhen));
-                                       if (exprType((Node *) w->result) != casetype)
-                                               return -1;
-                                       if (exprTypmod((Node *) w->result) != typmod)
-                                               return -1;
-                               }
-                               return typmod;
-                       }
-                       break;
-               case T_CaseTestExpr:
-                       return ((CaseTestExpr *) expr)->typeMod;
-               case T_ArrayExpr:
-                       {
-                               /*
-                                * If all the elements agree on type/typmod, return that
-                                * typmod, else use -1
-                                */
-                               ArrayExpr  *arrayexpr = (ArrayExpr *) expr;
-                               Oid                     commontype;
-                               int32           typmod;
-                               ListCell   *elem;
-
-                               if (arrayexpr->elements == NIL)
-                                       return -1;
-                               typmod = exprTypmod((Node *) linitial(arrayexpr->elements));
-                               if (typmod < 0)
-                                       return -1;      /* no point in trying harder */
-                               if (arrayexpr->multidims)
-                                       commontype = arrayexpr->array_typeid;
-                               else
-                                       commontype = arrayexpr->element_typeid;
-                               foreach(elem, arrayexpr->elements)
-                               {
-                                       Node       *e = (Node *) lfirst(elem);
-
-                                       if (exprType(e) != commontype)
-                                               return -1;
-                                       if (exprTypmod(e) != typmod)
-                                               return -1;
-                               }
-                               return typmod;
-                       }
-                       break;
-               case T_CoalesceExpr:
-                       {
-                               /*
-                                * If all the alternatives agree on type/typmod, return that
-                                * typmod, else use -1
-                                */
-                               CoalesceExpr *cexpr = (CoalesceExpr *) expr;
-                               Oid                     coalescetype = cexpr->coalescetype;
-                               int32           typmod;
-                               ListCell   *arg;
-
-                               if (exprType((Node *) linitial(cexpr->args)) != coalescetype)
-                                       return -1;
-                               typmod = exprTypmod((Node *) linitial(cexpr->args));
-                               if (typmod < 0)
-                                       return -1;      /* no point in trying harder */
-                               for_each_cell(arg, lnext(list_head(cexpr->args)))
-                               {
-                                       Node       *e = (Node *) lfirst(arg);
-
-                                       if (exprType(e) != coalescetype)
-                                               return -1;
-                                       if (exprTypmod(e) != typmod)
-                                               return -1;
-                               }
-                               return typmod;
-                       }
-                       break;
-               case T_MinMaxExpr:
-                       {
-                               /*
-                                * If all the alternatives agree on type/typmod, return that
-                                * typmod, else use -1
-                                */
-                               MinMaxExpr *mexpr = (MinMaxExpr *) expr;
-                               Oid                     minmaxtype = mexpr->minmaxtype;
-                               int32           typmod;
-                               ListCell   *arg;
-
-                               if (exprType((Node *) linitial(mexpr->args)) != minmaxtype)
-                                       return -1;
-                               typmod = exprTypmod((Node *) linitial(mexpr->args));
-                               if (typmod < 0)
-                                       return -1;      /* no point in trying harder */
-                               for_each_cell(arg, lnext(list_head(mexpr->args)))
-                               {
-                                       Node       *e = (Node *) lfirst(arg);
-
-                                       if (exprType(e) != minmaxtype)
-                                               return -1;
-                                       if (exprTypmod(e) != typmod)
-                                               return -1;
-                               }
-                               return typmod;
-                       }
-                       break;
-               case T_NullIfExpr:
-                       {
-                               NullIfExpr *nexpr = (NullIfExpr *) expr;
-
-                               return exprTypmod((Node *) linitial(nexpr->args));
-                       }
-                       break;
-               case T_CoerceToDomain:
-                       return ((CoerceToDomain *) expr)->resulttypmod;
-               case T_CoerceToDomainValue:
-                       return ((CoerceToDomainValue *) expr)->typeMod;
-               case T_SetToDefault:
-                       return ((SetToDefault *) expr)->typeMod;
-               default:
-                       break;
-       }
-       return -1;
-}
-
-/*
- * exprIsLengthCoercion
- *             Detect whether an expression tree is an application of a datatype's
- *             typmod-coercion function.  Optionally extract the result's typmod.
- *
- * If coercedTypmod is not NULL, the typmod is stored there if the expression
- * is a length-coercion function, else -1 is stored there.
- *
- * Note that a combined type-and-length coercion will be treated as a
- * length coercion by this routine.
- */
-bool
-exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
-{
-       if (coercedTypmod != NULL)
-               *coercedTypmod = -1;    /* default result on failure */
-
-       /*
-        * Scalar-type length coercions are FuncExprs, array-type length coercions
-        * are ArrayCoerceExprs
-        */
-       if (expr && IsA(expr, FuncExpr))
-       {
-               FuncExpr   *func = (FuncExpr *) expr;
-               int                     nargs;
-               Const      *second_arg;
-
-               /*
-                * If it didn't come from a coercion context, reject.
-                */
-               if (func->funcformat != COERCE_EXPLICIT_CAST &&
-                       func->funcformat != COERCE_IMPLICIT_CAST)
-                       return false;
-
-               /*
-                * If it's not a two-argument or three-argument function with the
-                * second argument being an int4 constant, it can't have been created
-                * from a length coercion (it must be a type coercion, instead).
-                */
-               nargs = list_length(func->args);
-               if (nargs < 2 || nargs > 3)
-                       return false;
-
-               second_arg = (Const *) lsecond(func->args);
-               if (!IsA(second_arg, Const) ||
-                       second_arg->consttype != INT4OID ||
-                       second_arg->constisnull)
-                       return false;
-
-               /*
-                * OK, it is indeed a length-coercion function.
-                */
-               if (coercedTypmod != NULL)
-                       *coercedTypmod = DatumGetInt32(second_arg->constvalue);
-
-               return true;
-       }
-
-       if (expr && IsA(expr, ArrayCoerceExpr))
-       {
-               ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) expr;
-
-               /* It's not a length coercion unless there's a nondefault typmod */
-               if (acoerce->resulttypmod < 0)
-                       return false;
-
-               /*
-                * OK, it is indeed a length-coercion expression.
-                */
-               if (coercedTypmod != NULL)
-                       *coercedTypmod = acoerce->resulttypmod;
-
-               return true;
-       }
-
-       return false;
-}
-
 /*
  * Handle an explicit CAST construct.
  *
index 785e8816a94245f4cf9d7e02e817d779c8569afc..b1de6264aa58e123045511324f9127c3b6af6df5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.204 2008/07/30 17:05:04 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.205 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,9 +20,9 @@
 #include "catalog/pg_type.h"
 #include "funcapi.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/parse_agg.h"
 #include "parser/parse_coerce.h"
-#include "parser/parse_expr.h"
 #include "parser/parse_func.h"
 #include "parser/parse_relation.h"
 #include "parser/parse_target.h"
index c13996711c352e926ffab151d54e80ec74dd746e..8cc531b350ac277154da575a5c4ec1b49fffa6cf 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.100 2008/04/21 00:26:45 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.101 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 #include "catalog/pg_type.h"
 #include "mb/pg_wchar.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/parsetree.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
index 055574ff982d791282d8502c7bc50d2fb927e7e6..f27615603b2fa4fb64226f1c43faced5314f7811 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.103 2008/08/02 21:32:00 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.104 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,8 +18,8 @@
 #include "catalog/pg_operator.h"
 #include "catalog/pg_type.h"
 #include "lib/stringinfo.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/parse_coerce.h"
-#include "parser/parse_expr.h"
 #include "parser/parse_func.h"
 #include "parser/parse_oper.h"
 #include "parser/parse_type.h"
index 114d2a0e2499eb0326d960366b2a1cb0332f34c9..7bd53e2a94b0b704698985cf21be5b0a24e41da9 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.132 2008/05/12 00:00:50 alvherre Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.133 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,8 +23,8 @@
 #include "catalog/pg_type.h"
 #include "funcapi.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/parsetree.h"
-#include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
 #include "parser/parse_type.h"
 #include "utils/builtins.h"
index f6cfacd12aa0d14ebf5a45261ddb1cb80421cfd5..70acb8382a8b79998aaf8365c524c6a2c787192b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.160 2008/04/29 14:59:17 alvherre Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.161 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,7 @@
 #include "funcapi.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/parsetree.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
index bbdea4642cc10f64c7a2b5ef87a5a2e077ee2eaf..4bab055269746bcf131a83657e1d7671543aa9aa 100644 (file)
@@ -19,7 +19,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.14 2008/07/16 01:30:22 tgl Exp $
+ *     $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.15 2008/08/25 22:42:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,7 +40,7 @@
 #include "commands/tablespace.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
-#include "optimizer/clauses.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/analyze.h"
 #include "parser/gramparse.h"
 #include "parser/parse_clause.h"
index 1491aee1635f0d8543941abe243d5df0457a6f49..7ca90a5485776f87338d9902b9c887a3fbd2b26e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.128 2008/08/11 11:05:11 heikki Exp $
+ *       $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.129 2008/08/25 22:42:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,8 +20,7 @@
 #include "catalog/namespace.h"
 #include "catalog/pg_rewrite.h"
 #include "miscadmin.h"
-#include "optimizer/clauses.h"
-#include "parser/parse_expr.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/parse_utilcmd.h"
 #include "rewrite/rewriteDefine.h"
 #include "rewrite/rewriteManip.h"
index 215c9b503654c6fb0b2ae638d971659eb24557f4..5269fa63cd9bedfc82bf84da93394e99071d5989 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.177 2008/01/01 19:45:51 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.178 2008/08/25 22:42:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "access/heapam.h"
 #include "catalog/pg_type.h"
 #include "nodes/makefuncs.h"
-#include "optimizer/clauses.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/analyze.h"
 #include "parser/parse_coerce.h"
-#include "parser/parse_expr.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteDefine.h"
 #include "rewrite/rewriteHandler.h"
index baa9330016fad13962d062783c11888a4e76e7cb..840118bbf75acc64cad3f4a8b234a373c057271e 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.110 2008/08/22 00:16:04 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.111 2008/08/25 22:42:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -15,6 +15,7 @@
 
 #include "catalog/pg_type.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_relation.h"
index 3c62e7a972dcd6b6cdf0b2f99c61a19dfe449b69..bad6fcac694ab10938276a3b19ea798e10e3bb8a 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.280 2008/08/22 00:16:04 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.281 2008/08/25 22:42:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "executor/spi.h"
 #include "funcapi.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/tlist.h"
 #include "parser/gramparse.h"
 #include "parser/keywords.h"
-#include "parser/parse_expr.h"
 #include "parser/parse_func.h"
 #include "parser/parse_oper.h"
 #include "parser/parsetree.h"
index d484221232c4771c1d3d1a6b0f0ff07728e88605..7524e2d5809b0e2a78fa9755a0f207d9cc99c194 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.252 2008/08/16 00:01:36 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.253 2008/08/25 22:42:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -97,6 +97,7 @@
 #include "catalog/pg_type.h"
 #include "mb/pg_wchar.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/var.h"
 #include "parser/parse_coerce.h"
-#include "parser/parse_expr.h"
 #include "parser/parsetree.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
@@ -3613,9 +3613,8 @@ convert_string_datum(Datum value, Oid typid)
 #if _MSC_VER == 1400                   /* VS.Net 2005 */
 
                /*
-                *
-                * http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx
-                * ?FeedbackID=99694 */
+                * http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=99694
+                */
                {
                        char            x[1];
 
index 799e9a283aafb6eb9e47d4a5950f74a605eb8244..fd0c0ee80f8a1db40eea6a1f7133decd0c9b7843 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.75 2008/07/03 00:04:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.76 2008/08/25 22:42:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -74,7 +74,7 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/execnodes.h"
-#include "parser/parse_expr.h"
+#include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
index fd0433bb3796387d84029b2cec9f77f03f57ca0c..c0dc3649ac0e308730b000059c636cb3fc9ecc1a 100644 (file)
@@ -33,7 +33,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.19 2008/07/18 20:26:06 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.20 2008/08/25 22:42:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -43,7 +43,7 @@
 #include "access/transam.h"
 #include "catalog/namespace.h"
 #include "executor/executor.h"
-#include "optimizer/clauses.h"
+#include "nodes/nodeFuncs.h"
 #include "storage/lmgr.h"
 #include "tcop/pquery.h"
 #include "tcop/tcopprot.h"
index cd23bae077953d623b86013525e2d1bb942c801d..82dbb8e97076109fdc052d82c54b71f30de7c1e6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.121 2008/07/16 16:55:23 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.122 2008/08/25 22:42:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,7 +21,7 @@
 #include "executor/functions.h"
 #include "lib/stringinfo.h"
 #include "miscadmin.h"
-#include "parser/parse_expr.h"
+#include "nodes/nodeFuncs.h"
 #include "pgstat.h"
 #include "utils/builtins.h"
 #include "utils/fmgrtab.h"
index 6ff1b90ffcdc5d58a1992094bfe59e76caf249ed..52b3bafb114ba4dd502703575226222c04374f34 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (c) 2002-2008, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.41 2008/07/18 03:32:52 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.42 2008/08/25 22:42:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,8 +18,8 @@
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 #include "funcapi.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/parse_coerce.h"
-#include "parser/parse_expr.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
index 375301a0dcdc858359bacb1eed7ab1f2451c15f3..f699fc1b68ea28bde3abf171e3d22195d73cc289 100644 (file)
@@ -1,23 +1,50 @@
 /*-------------------------------------------------------------------------
  *
  * nodeFuncs.h
- *
- *
+ *             Various general-purpose manipulations of Node trees
  *
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/nodeFuncs.h,v 1.26 2008/01/01 19:45:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodeFuncs.h,v 1.27 2008/08/25 22:42:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef NODEFUNCS_H
 #define NODEFUNCS_H
 
-#include "nodes/primnodes.h"
+#include "nodes/parsenodes.h"
+
+
+/* flags bits for query_tree_walker and query_tree_mutator */
+#define QTW_IGNORE_RT_SUBQUERIES       0x01            /* subqueries in rtable */
+#define QTW_IGNORE_JOINALIASES         0x02            /* JOIN alias var lists */
+#define QTW_DONT_COPY_QUERY                    0x04            /* do not copy top Query */
+
+
+extern Oid     exprType(Node *expr);
+extern int32 exprTypmod(Node *expr);
+extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod);
+extern bool expression_returns_set(Node *clause);
+
+extern bool expression_tree_walker(Node *node, bool (*walker) (),
+                                                                                          void *context);
+extern Node *expression_tree_mutator(Node *node, Node *(*mutator) (),
+                                                                                                void *context);
+
+extern bool query_tree_walker(Query *query, bool (*walker) (),
+                                                                                 void *context, int flags);
+extern Query *query_tree_mutator(Query *query, Node *(*mutator) (),
+                                                                                        void *context, int flags);
+
+extern bool range_table_walker(List *rtable, bool (*walker) (),
+                                                                                  void *context, int flags);
+extern List *range_table_mutator(List *rtable, Node *(*mutator) (),
+                                                                                        void *context, int flags);
 
-extern bool single_node(Node *node);
-extern bool var_is_outer(Var *var);
-extern bool var_is_rel(Var *var);
+extern bool query_or_expression_tree_walker(Node *node, bool (*walker) (),
+                                                                                                  void *context, int flags);
+extern Node *query_or_expression_tree_mutator(Node *node, Node *(*mutator) (),
+                                                                                                  void *context, int flags);
 
 #endif   /* NODEFUNCS_H */
index 1ea3d701fe9c1edc4f70e40294ab957a83c05784..105924bb227dc3972cbdc22619bf0850a86c83d3 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.93 2008/08/22 00:16:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.94 2008/08/25 22:42:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -49,7 +49,6 @@ extern List *make_ands_implicit(Expr *clause);
 extern bool contain_agg_clause(Node *clause);
 extern void count_agg_clauses(Node *clause, AggClauseCounts *counts);
 
-extern bool expression_returns_set(Node *clause);
 extern double expression_returns_set_rows(Node *clause);
 
 extern bool contain_subplans(Node *clause);
@@ -80,29 +79,4 @@ extern Node *estimate_expression_value(PlannerInfo *root, Node *node);
 
 extern Query *inline_set_returning_function(PlannerInfo *root, Node *node);
 
-extern bool expression_tree_walker(Node *node, bool (*walker) (),
-                                                                                          void *context);
-extern Node *expression_tree_mutator(Node *node, Node *(*mutator) (),
-                                                                                                void *context);
-
-/* flags bits for query_tree_walker and query_tree_mutator */
-#define QTW_IGNORE_RT_SUBQUERIES       0x01            /* subqueries in rtable */
-#define QTW_IGNORE_JOINALIASES         0x02            /* JOIN alias var lists */
-#define QTW_DONT_COPY_QUERY                    0x04            /* do not copy top Query */
-
-extern bool query_tree_walker(Query *query, bool (*walker) (),
-                                                                                 void *context, int flags);
-extern Query *query_tree_mutator(Query *query, Node *(*mutator) (),
-                                                                                        void *context, int flags);
-
-extern bool range_table_walker(List *rtable, bool (*walker) (),
-                                                                                  void *context, int flags);
-extern List *range_table_mutator(List *rtable, Node *(*mutator) (),
-                                                                                        void *context, int flags);
-
-extern bool query_or_expression_tree_walker(Node *node, bool (*walker) (),
-                                                                                                  void *context, int flags);
-extern Node *query_or_expression_tree_mutator(Node *node, Node *(*mutator) (),
-                                                                                                  void *context, int flags);
-
 #endif   /* CLAUSES_H */
index 6e70583ba022b948a5722965ce36660c9aa1f204..cb921fd2fbd3b997374fcbd8ec9d26b372294989 100644 (file)
@@ -1,13 +1,12 @@
 /*-------------------------------------------------------------------------
  *
  * parse_expr.h
- *
- *
+ *       handle expressions in parser
  *
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/parser/parse_expr.h,v 1.38 2008/01/01 19:45:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_expr.h,v 1.39 2008/08/25 22:42:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "parser/parse_node.h"
 
-
 /* GUC parameters */
 extern bool Transform_null_equals;
 
-
 extern Node *transformExpr(ParseState *pstate, Node *expr);
-extern Oid     exprType(Node *expr);
-extern int32 exprTypmod(Node *expr);
-extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod);
 
 #endif   /* PARSE_EXPR_H */
index f4088616f2637ff20ec6a411e22f4a98b1497663..3cc3d1a3b0794cc61eee265079bc9df74575440e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.216 2008/05/16 18:34:51 tgl Exp $
+ *       $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.217 2008/08/25 22:42:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,8 +23,7 @@
 #include "catalog/pg_type.h"
 #include "executor/spi_priv.h"
 #include "funcapi.h"
-#include "optimizer/clauses.h"
-#include "parser/parse_expr.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/scansup.h"
 #include "tcop/tcopprot.h"
 #include "utils/array.h"