From e5536e77a50e2b6a5881a2ce9ef1c6debcb5d909 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 25 Aug 2008 22:42:34 +0000 Subject: [PATCH] Move exprType(), exprTypmod(), expression_tree_walker(), and related routines 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. --- src/backend/catalog/dependency.c | 4 +- src/backend/catalog/heap.c | 4 +- src/backend/catalog/index.c | 4 +- src/backend/commands/analyze.c | 4 +- src/backend/commands/indexcmds.c | 4 +- src/backend/commands/prepare.c | 3 +- src/backend/commands/tablecmds.c | 3 +- src/backend/commands/view.c | 5 +- src/backend/executor/execMain.c | 4 +- src/backend/executor/execQual.c | 4 +- src/backend/executor/execTuples.c | 4 +- src/backend/executor/functions.c | 4 +- src/backend/executor/nodeAgg.c | 4 +- src/backend/nodes/README | 62 +- src/backend/nodes/nodeFuncs.c | 1719 ++++++++++++++++++++- src/backend/optimizer/path/allpaths.c | 4 +- src/backend/optimizer/path/costsize.c | 4 +- src/backend/optimizer/path/equivclass.c | 3 +- src/backend/optimizer/path/pathkeys.c | 4 +- src/backend/optimizer/path/tidpath.c | 4 +- src/backend/optimizer/plan/createplan.c | 4 +- src/backend/optimizer/plan/planagg.c | 4 +- src/backend/optimizer/plan/setrefs.c | 4 +- src/backend/optimizer/plan/subselect.c | 4 +- src/backend/optimizer/prep/prepjointree.c | 4 +- src/backend/optimizer/prep/prepunion.c | 5 +- src/backend/optimizer/util/clauses.c | 1232 +-------------- src/backend/optimizer/util/plancat.c | 4 +- src/backend/optimizer/util/predtest.c | 4 +- src/backend/optimizer/util/tlist.c | 4 +- src/backend/optimizer/util/var.c | 4 +- src/backend/parser/analyze.c | 5 +- src/backend/parser/parse_agg.c | 4 +- src/backend/parser/parse_clause.c | 4 +- src/backend/parser/parse_coerce.c | 5 +- src/backend/parser/parse_expr.c | 485 +----- src/backend/parser/parse_func.c | 4 +- src/backend/parser/parse_node.c | 3 +- src/backend/parser/parse_oper.c | 4 +- src/backend/parser/parse_relation.c | 4 +- src/backend/parser/parse_target.c | 3 +- src/backend/parser/parse_utilcmd.c | 4 +- src/backend/rewrite/rewriteDefine.c | 5 +- src/backend/rewrite/rewriteHandler.c | 5 +- src/backend/rewrite/rewriteManip.c | 3 +- src/backend/utils/adt/ruleutils.c | 4 +- src/backend/utils/adt/selfuncs.c | 9 +- src/backend/utils/adt/xml.c | 4 +- src/backend/utils/cache/plancache.c | 4 +- src/backend/utils/fmgr/fmgr.c | 4 +- src/backend/utils/fmgr/funcapi.c | 4 +- src/include/nodes/nodeFuncs.h | 41 +- src/include/optimizer/clauses.h | 28 +- src/include/parser/parse_expr.h | 10 +- src/pl/plpgsql/src/pl_exec.c | 5 +- 55 files changed, 1865 insertions(+), 1910 deletions(-) diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 0c85ac785f..3521f5ec95 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -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" diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index c5cea2f67f..499929ef10 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -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" diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index abe8d29ac1..1847f023e4 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -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" diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 3b8423999a..c207e502ee 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -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" diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 1427b2a10e..cbf440fc43 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -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" diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index fe716c5e9f..2fca3a5e81 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -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" diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 5167a40927..a8ae2e4be1 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -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" diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index e6ec1508ab..5d207861dc 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -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" diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 3072cf7b04..49fa4156de 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -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" diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 57b2df9c00..57b6445c0f 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -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" diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 6ed210b7a6..357d99e36f 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -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" diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 81f0c8e731..3ce4d0f321 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -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" diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 9bcff0f8df..fa49862912 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -74,10 +74,10 @@ #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" diff --git a/src/backend/nodes/README b/src/backend/nodes/README index b1b95ffcde..67e7badc1f 100644 --- a/src/backend/nodes/README +++ b/src/backend/nodes/README @@ -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 - diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index c72332a611..7944936ba6 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -1,74 +1,1725 @@ /*------------------------------------------------------------------------- * * 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.) */ -bool -single_node(Node *node) +Oid +exprType(Node *expr) { - if (IsA(node, Const) || - IsA(node, Var) || - IsA(node, Param)) - return true; - else - return false; + 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; } -/***************************************************************************** - * VAR nodes - *****************************************************************************/ +/* + * 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; +} /* - * var_is_outer - * var_is_inner - * var_is_mat - * var_is_rel + * exprIsLengthCoercion + * Detect whether an expression tree is an application of a datatype's + * typmod-coercion function. Optionally extract the result's typmod. * - * 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 + * 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 -var_is_outer(Var *var) +exprIsLengthCoercion(Node *expr, int32 *coercedTypmod) { - return (bool) (var->varno == OUTER); + 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; +} + +/* + * 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 -var_is_inner(Var *var) +expression_returns_set_walker(Node *node, void *context) { - return (bool) (var->varno == INNER); + 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); } + +/* + * 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 -var_is_rel(Var *var) +expression_tree_walker(Node *node, + bool (*walker) (), + void *context) { - return (bool) - !(var_is_inner(var) || var_is_outer(var)); + 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); } diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index b13371e00e..3dc41c6807 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -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 +#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" diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 487de9ee93..49f81845c9 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -65,12 +65,12 @@ #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" diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index c4459e6e3e..0847b95574 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -10,13 +10,14 @@ * 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" diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index ccb23834de..c68785108a 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -20,13 +20,13 @@ #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" diff --git a/src/backend/optimizer/path/tidpath.c b/src/backend/optimizer/path/tidpath.c index 3def7c3738..7eada8d908 100644 --- a/src/backend/optimizer/path/tidpath.c +++ b/src/backend/optimizer/path/tidpath.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -39,10 +39,10 @@ #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); diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index ea85fe016e..a0ca92bd73 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -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" diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c index a6b4b1df66..8a6b2ad034 100644 --- a/src/backend/optimizer/plan/planagg.c +++ b/src/backend/optimizer/plan/planagg.c @@ -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" diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 7bcbabd101..b9d5643da8 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -17,10 +17,10 @@ #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" diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index ee2d936b34..42ac74e1a2 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -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" diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index 24e9fdb0b0..965856385d 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -16,19 +16,19 @@ * * * 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" diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 2fcdf0592f..c07ca4434a 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -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" diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 6a06b0806c..c015be9e9b 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -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 @@ -28,16 +28,14 @@ #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); -} diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 30e841b487..8f025ac3a4 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -25,11 +25,11 @@ #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" diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c index 4a1a6056e3..6d9934b578 100644 --- a/src/backend/optimizer/util/predtest.c +++ b/src/backend/optimizer/util/predtest.c @@ -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" diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c index b2fb112ebe..2fd16afb5f 100644 --- a/src/backend/optimizer/util/tlist.c +++ b/src/backend/optimizer/util/tlist.c @@ -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" diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index f9bd59c799..85f34e4942 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -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" diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 3de232ba71..2086c3321f 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -26,13 +26,12 @@ #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" diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index b5fbd0f78d..b635c3260c 100644 --- a/src/backend/parser/parse_agg.c +++ b/src/backend/parser/parse_agg.c @@ -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" diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 79b45414d4..aa0b9fd09e 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -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" diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index df1fb8526d..1244498ffb 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -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" diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 6309525cab..4257b91a8e 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -17,13 +17,10 @@ #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. * diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 785e8816a9..b1de6264aa 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -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" diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index c13996711c..8cc531b350 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -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" diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index 055574ff98..f27615603b 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -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" diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 114d2a0e24..7bd53e2a94 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -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" diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index f6cfacd12a..70acb8382a 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -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" diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index bbdea4642c..4bab055269 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -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" diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index 1491aee163..7ca90a5485 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -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" diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 215c9b5036..5269fa63cd 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -16,10 +16,9 @@ #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" diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c index baa9330016..840118bbf7 100644 --- a/src/backend/rewrite/rewriteManip.c +++ b/src/backend/rewrite/rewriteManip.c @@ -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" diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 3c62e7a972..bad6fcac69 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -33,11 +33,11 @@ #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" diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index d484221232..7524e2d580 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -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" @@ -106,7 +107,6 @@ #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]; diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index 799e9a283a..fd0c0ee80f 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -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" diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c index fd0433bb37..c0dc3649ac 100644 --- a/src/backend/utils/cache/plancache.c +++ b/src/backend/utils/cache/plancache.c @@ -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" diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index cd23bae077..82dbb8e970 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -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" diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c index 6ff1b90ffc..52b3bafb11 100644 --- a/src/backend/utils/fmgr/funcapi.c +++ b/src/backend/utils/fmgr/funcapi.c @@ -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" diff --git a/src/include/nodes/nodeFuncs.h b/src/include/nodes/nodeFuncs.h index 375301a0dc..f699fc1b68 100644 --- a/src/include/nodes/nodeFuncs.h +++ b/src/include/nodes/nodeFuncs.h @@ -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" -extern bool single_node(Node *node); -extern bool var_is_outer(Var *var); -extern bool var_is_rel(Var *var); + +/* 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 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 */ diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h index 1ea3d701fe..105924bb22 100644 --- a/src/include/optimizer/clauses.h +++ b/src/include/optimizer/clauses.h @@ -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 */ diff --git a/src/include/parser/parse_expr.h b/src/include/parser/parse_expr.h index 6e70583ba0..cb921fd2fb 100644 --- a/src/include/parser/parse_expr.h +++ b/src/include/parser/parse_expr.h @@ -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 $ * *------------------------------------------------------------------------- */ @@ -16,14 +15,9 @@ #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 */ diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index f4088616f2..3cc3d1a3b0 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -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"